summaryrefslogtreecommitdiffstats
path: root/sys/netatm/spans
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 /sys/netatm/spans
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 'sys/netatm/spans')
-rw-r--r--sys/netatm/spans/spans_arp.c1133
-rw-r--r--sys/netatm/spans/spans_cls.c848
-rw-r--r--sys/netatm/spans/spans_cls.h188
-rw-r--r--sys/netatm/spans/spans_if.c1336
-rw-r--r--sys/netatm/spans/spans_kxdr.c684
-rw-r--r--sys/netatm/spans/spans_msg.c1633
-rw-r--r--sys/netatm/spans/spans_print.c1062
-rw-r--r--sys/netatm/spans/spans_proto.c558
-rw-r--r--sys/netatm/spans/spans_subr.c494
-rw-r--r--sys/netatm/spans/spans_util.c477
-rw-r--r--sys/netatm/spans/spans_var.h259
-rw-r--r--sys/netatm/spans/spans_xdr.x513
12 files changed, 9185 insertions, 0 deletions
diff --git a/sys/netatm/spans/spans_arp.c b/sys/netatm/spans/spans_arp.c
new file mode 100644
index 0000000..5a2443a
--- /dev/null
+++ b/sys/netatm/spans/spans_arp.c
@@ -0,0 +1,1133 @@
+/*
+ *
+ * ===================================
+ * 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: spans_arp.c,v 1.9 1998/06/29 22:03:12 mks Exp $
+ *
+ */
+
+/*
+ * SPANS Signalling Manager
+ * ---------------------------
+ *
+ * SPANS CLS - ARP support
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: spans_arp.c,v 1.9 1998/06/29 22:03:12 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/ipatm/ipatm_var.h>
+#include <netatm/ipatm/ipatm_serv.h>
+#include "spans_xdr.h"
+#include <netatm/spans/spans_var.h>
+#include <netatm/spans/spans_cls.h>
+
+
+/*
+ * Global variables
+ */
+struct spansarp *spansarp_arptab[SPANSARP_HASHSIZ] = {NULL};
+
+
+/*
+ * Local functions
+ */
+static int spansarp_request __P((struct spansarp *));
+static void spansarp_aging __P((struct atm_time *));
+static void spansarp_retry __P((struct atm_time *));
+
+/*
+ * Local variables
+ */
+static struct atm_time spansarp_timer = {0, 0}; /* Aging timer */
+static struct atm_time spansarp_rtimer = {0, 0}; /* Retry timer */
+
+static struct spansarp *spansarp_retry_head = NULL; /* Retry chain */
+
+static struct sp_info spansarp_pool = {
+ "spans arp pool", /* si_name */
+ sizeof(struct spansarp), /* si_blksiz */
+ 10, /* si_blkcnt */
+ 100 /* si_maxallow */
+};
+
+
+/*
+ * Process a new outgoing SVC requiring SPANS ARP support
+ *
+ * This function is called by an endpoint wishing to resolve a destination
+ * IP address to an ATM address in order to open an SVC to that destination.
+ * If a valid mapping is already in our cache, then we just tell the caller
+ * about it and that's that. Otherwise, we have to allocate a new arp entry
+ * and issue a query for the mapping.
+ *
+ * Arguments:
+ * ivp pointer to SVC's IPVCC control block
+ * dst pointer to destination IP address
+ *
+ * Returns:
+ * MAP_VALID - Got the answer, returned via iv_arpent field.
+ * MAP_PROCEEDING - OK so far, querying for peer's mapping
+ * MAP_FAILED - error, unable to allocate resources
+ *
+ */
+int
+spansarp_svcout(ivp, dst)
+ struct ipvcc *ivp;
+ struct in_addr *dst;
+{
+ struct spanscls *clp;
+ struct spansarp *sap;
+ int s;
+
+ ivp->iv_arpent = NULL;
+
+ /*
+ * Lookup destination address
+ */
+ s = splnet();
+ SPANSARP_LOOKUP(dst->s_addr, sap);
+
+ if (sap) {
+ /*
+ * Link this vcc to entry queue
+ */
+ LINK2TAIL(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext);
+
+ /*
+ * If entry is valid, we're done
+ */
+ if (sap->sa_flags & SAF_VALID) {
+ ivp->iv_arpent = (struct arpmap *)sap;
+ (void) splx(s);
+ return (MAP_VALID);
+ }
+
+ /*
+ * We're already looking for this address
+ */
+ (void) splx(s);
+ return (MAP_PROCEEDING);
+ }
+
+ /*
+ * Need a new arp entry - first, find the cls instance
+ * corresponding to the requestor's IP interface.
+ */
+ for (clp = spanscls_head; clp; clp = clp->cls_next) {
+ if (clp->cls_ipnif == ivp->iv_ipnif)
+ break;
+ }
+ if (clp == NULL) {
+ (void) splx(s);
+ return (MAP_FAILED);
+ }
+
+ /*
+ * Now get the new arp entry
+ */
+ sap = (struct spansarp *)atm_allocate(&spansarp_pool);
+ if (sap == NULL) {
+ (void) splx(s);
+ return (MAP_FAILED);
+ }
+
+ /*
+ * Get entry set up
+ */
+ sap->sa_dstip.s_addr = dst->s_addr;
+ sap->sa_dstatm.address_format = T_ATM_ABSENT;
+ sap->sa_dstatm.address_length = 0;
+ sap->sa_dstatmsub.address_format = T_ATM_ABSENT;
+ sap->sa_dstatmsub.address_length = 0;
+ sap->sa_cls = clp;
+ sap->sa_origin = SAO_LOOKUP;
+
+ /*
+ * Link ipvcc to arp entry for later notification
+ */
+ LINK2TAIL(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext);
+
+ /*
+ * Add arp entry to table
+ */
+ SPANSARP_ADD(sap);
+
+ /*
+ * Add arp entry to retry list and start retry timer if needed
+ */
+ LINK2TAIL(sap, struct spansarp, spansarp_retry_head, sa_rnext);
+ if ((spansarp_rtimer.ti_flag & TIF_QUEUED) == 0)
+ atm_timeout(&spansarp_rtimer, SPANSARP_RETRY, spansarp_retry);
+
+ /*
+ * Issue arp request for this address
+ */
+ (void) spansarp_request(sap);
+
+ (void) splx(s);
+ return (MAP_PROCEEDING);
+}
+
+
+/*
+ * Process a new incoming SVC requiring SPANS ARP support
+ *
+ * This function is called by an endpoint wishing to resolve a destination
+ * ATM address to its IP address for an incoming call in order to allow a
+ * bi-directional flow of IP packets on the SVC.
+ *
+ * SPANS ARP does not provide reverse mapping facilities and only supports
+ * uni-directional SVCs. Thus, we lie a little to IP and always return a
+ * MAP_PROCEEDING indication, but we will never later notify IP of a
+ * MAP_VALID condition.
+ *
+ * Arguments:
+ * ivp pointer to SVC's IPVCC control block
+ * dst pointer to destination ATM address
+ * dstsub pointer to destination ATM subaddress
+ *
+ * Returns:
+ * MAP_VALID - Got the answer, returned via iv_arpent field.
+ * MAP_PROCEEDING - OK so far, querying for peer's mapping
+ * MAP_FAILED - error, unable to allocate resources
+ *
+ */
+int
+spansarp_svcin(ivp, dst, dstsub)
+ struct ipvcc *ivp;
+ Atm_addr *dst;
+ Atm_addr *dstsub;
+{
+ /*
+ * Clear ARP entry field
+ */
+ ivp->iv_arpent = NULL;
+
+ return (MAP_PROCEEDING);
+}
+
+
+/*
+ * SPANS ARP SVC activation notification
+ *
+ * This function is called when a previously opened SVC has successfully
+ * been connected.
+ *
+ * Arguments:
+ * ivp pointer to SVC's IPVCC control block
+ *
+ * Returns:
+ * 0 activation processing successful
+ * errno activation failed - reason indicated
+ *
+ */
+int
+spansarp_svcactive(ivp)
+ struct ipvcc *ivp;
+{
+ struct spansarp *sap;
+ int s = splnet();
+
+ /*
+ * Find an entry for the destination address
+ */
+ SPANSARP_LOOKUP(ivp->iv_dst.s_addr, sap);
+ if (sap) {
+ /*
+ * IP is finished with entry, so remove IP VCC from chain
+ */
+ UNLINK(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext);
+ ivp->iv_arpent = NULL;
+
+ /*
+ * This seems like a reasonable reason to refresh the entry
+ */
+ sap->sa_reftime = 0;
+ }
+
+ (void) splx(s);
+ return (0);
+}
+
+
+/*
+ * SPANS ARP supported VCC is closing
+ *
+ * This function is called just prior to a user closing a VCC which
+ * supports SPANS ARP. We'll sever our links to the VCC and then
+ * figure out how much more cleanup we need to do for now.
+ *
+ * Arguments:
+ * ivp pointer to VCC's IPVCC control block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+spansarp_vcclose(ivp)
+ struct ipvcc *ivp;
+{
+ struct spansarp *sap;
+ int s = splnet();
+
+ /*
+ * Get spansarp entry
+ */
+ SPANSARP_LOOKUP(ivp->iv_dst.s_addr, sap);
+ if (sap == NULL) {
+ (void) splx(s);
+ return;
+ }
+
+ /*
+ * Remove IP VCC from chain
+ */
+ UNLINK(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext);
+ ivp->iv_arpent = NULL;
+
+ /*
+ * If entry is currently valid or in use, not much else for us to do
+ */
+ if ((sap->sa_flags & (SAF_VALID | SAF_LOCKED)) ||
+ (sap->sa_origin >= SAO_PERM)) {
+ (void) splx(s);
+ return;
+ }
+
+ /*
+ * If there are still other VCCs waiting, exit
+ */
+ if (sap->sa_ivp) {
+ (void) splx(s);
+ return;
+ }
+
+ /*
+ * Noone else waiting, so remove entry from the retry chain
+ */
+ UNLINK(sap, struct spansarp, spansarp_retry_head, sa_rnext);
+
+ /*
+ * Free entry
+ */
+ SPANSARP_DELETE(sap);
+ atm_free((caddr_t)sap);
+ (void) splx(s);
+}
+
+
+/*
+ * Process module unloading notification
+ *
+ * Called whenever the spans module is about to be unloaded. All signalling
+ * instances will have been previously detached. All spansarp resources
+ * must be freed now.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+spansarp_stop()
+{
+ int i;
+
+ /*
+ * Make sure the arp table is empty
+ */
+ for (i = 0; i < SPANSARP_HASHSIZ; i++) {
+ if (spansarp_arptab[i] != NULL)
+ panic("spansarp_stop: arp table not empty");
+ }
+
+ /*
+ * Cancel timers
+ */
+ (void) atm_untimeout(&spansarp_timer);
+ (void) atm_untimeout(&spansarp_rtimer);
+
+ /*
+ * Free our storage pools
+ */
+ atm_release_pool(&spansarp_pool);
+}
+
+
+/*
+ * Process IP Network Interface Activation
+ *
+ * Called whenever an IP network interface becomes active.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * clp pointer to CLS interface
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+spansarp_ipact(clp)
+ struct spanscls *clp;
+{
+ /*
+ * Make sure aging timer is running
+ */
+ if ((spansarp_timer.ti_flag & TIF_QUEUED) == 0)
+ atm_timeout(&spansarp_timer, SPANSARP_AGING, spansarp_aging);
+}
+
+
+/*
+ * Process IP Network Interface Deactivation
+ *
+ * Called whenever an IP network interface becomes inactive.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * clp pointer to CLS interface
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+spansarp_ipdact(clp)
+ struct spanscls *clp;
+{
+ struct spanscls *clp2;
+ struct spansarp *sap, *snext;
+ int i;
+
+ /*
+ * Delete all interface entries
+ */
+ for (i = 0; i < SPANSARP_HASHSIZ; i++) {
+ for (sap = spansarp_arptab[i]; sap; sap = snext) {
+ snext = sap->sa_next;
+
+ /*
+ * Clean up entries for this interface
+ */
+ if (sap->sa_cls != clp)
+ continue;
+
+ /*
+ * All VCCs better be gone by now
+ */
+ if (sap->sa_ivp)
+ panic("spansarp_ipdact: entry not empty");
+
+ /*
+ * Remove entry from the retry chain
+ */
+ UNLINK(sap, struct spansarp,
+ spansarp_retry_head, sa_rnext);
+
+ /*
+ * Delete entry from arp table
+ */
+ SPANSARP_DELETE(sap);
+ atm_free((caddr_t)sap);
+ }
+ }
+
+ /*
+ * Stop aging timer if this is the last active interface
+ */
+ for (clp2 = spanscls_head; clp2; clp2 = clp2->cls_next) {
+ if ((clp != clp2) && (clp2->cls_ipnif))
+ break;
+ }
+ if (clp2 == NULL)
+ (void) atm_untimeout(&spansarp_timer);
+}
+
+
+/*
+ * Issue a SPANS ARP request packet
+ *
+ * Arguments:
+ * sap pointer to arp table entry
+ *
+ * Returns:
+ * 0 packet was successfully sent
+ * else unable to send packet
+ *
+ */
+static int
+spansarp_request(sap)
+ struct spansarp *sap;
+{
+ struct spanscls *clp;
+ struct spans *spp;
+ struct spanscls_hdr *chp;
+ struct spansarp_hdr *ahp;
+ KBuffer *m;
+ struct ip_nif *inp;
+ int err;
+
+ clp = sap->sa_cls;
+ spp = clp->cls_spans;
+ inp = clp->cls_ipnif;
+
+ /*
+ * Make sure CLS VCC is open and that we know our addresses
+ */
+ if (clp->cls_state != CLS_OPEN)
+ return (1);
+ if (spp->sp_addr.address_format != T_ATM_SPANS_ADDR)
+ return (1);
+ if (inp == NULL)
+ return (1);
+
+ /*
+ * Get a buffer for pdu
+ */
+ KB_ALLOCPKT(m, ARP_PACKET_LEN, KB_F_NOWAIT, KB_T_DATA);
+ if (m == NULL)
+ return (1);
+
+ /*
+ * Place pdu at end of buffer
+ */
+ KB_PLENSET(m, ARP_PACKET_LEN);
+ KB_TAILALIGN(m, ARP_PACKET_LEN);
+ KB_DATASTART(m, chp, struct spanscls_hdr *);
+ ahp = (struct spansarp_hdr *)(chp + 1);
+
+ /*
+ * Build headers
+ */
+ spans_addr_copy(&spans_bcastaddr, &chp->ch_dst);
+ spans_addr_copy(spp->sp_addr.address, &chp->ch_src);
+ *(u_int *)&chp->ch_proto = *(u_int *)&spanscls_hdr.ch_proto;
+ *(u_int *)&chp->ch_dsap = *(u_int *)&spanscls_hdr.ch_dsap;
+ *(u_short *)&chp->ch_oui[1] = *(u_short *)&spanscls_hdr.ch_oui[1];
+ chp->ch_pid = htons(ETHERTYPE_ARP);
+
+
+ /*
+ * Build ARP packet
+ */
+ ahp->ah_hrd = htons(ARP_SPANS);
+ ahp->ah_pro = htons(ETHERTYPE_IP);
+ ahp->ah_hln = sizeof(spans_addr);
+ ahp->ah_pln = sizeof(struct in_addr);
+ ahp->ah_op = htons(ARP_REQUEST);
+ spans_addr_copy(spp->sp_addr.address, &ahp->ah_sha);
+ KM_COPY(&(IA_SIN(inp->inf_addr)->sin_addr), ahp->ah_spa,
+ sizeof(struct in_addr));
+ KM_COPY(&sap->sa_dstip, ahp->ah_tpa, sizeof(struct in_addr));
+
+ /*
+ * Now, send the pdu via the CLS service
+ */
+ err = atm_cm_cpcs_data(clp->cls_conn, m);
+ if (err) {
+ KB_FREEALL(m);
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * Process a SPANS ARP input packet
+ *
+ * Arguments:
+ * clp pointer to interface CLS control block
+ * m pointer to input packet buffer chain
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+spansarp_input(clp, m)
+ struct spanscls *clp;
+ KBuffer *m;
+{
+ struct spans *spp = clp->cls_spans;
+ struct spanscls_hdr *chp;
+ struct spansarp_hdr *ahp;
+ struct spansarp *sap;
+ struct ip_nif *inp = clp->cls_ipnif;
+ struct in_addr in_me, in_src, in_targ;
+ int s, err;
+
+ /*
+ * Make sure IP interface has been activated
+ */
+ if (inp == NULL)
+ goto free;
+
+ /*
+ * Get the packet together
+ */
+ if (KB_LEN(m) < ARP_PACKET_LEN) {
+ KB_PULLUP(m, ARP_PACKET_LEN, m);
+ if (m == 0)
+ return;
+ }
+ KB_DATASTART(m, chp, struct spanscls_hdr *);
+ ahp = (struct spansarp_hdr *)(chp + 1);
+
+ KM_COPY(ahp->ah_spa, &in_src, sizeof(struct in_addr));
+ KM_COPY(ahp->ah_tpa, &in_targ, sizeof(struct in_addr));
+ KM_COPY(&(IA_SIN(inp->inf_addr)->sin_addr), &in_me,
+ sizeof(struct in_addr));
+
+ /*
+ * Initial packet verification
+ */
+ if ((ahp->ah_hrd != htons(ARP_SPANS)) ||
+ (ahp->ah_pro != htons(ETHERTYPE_IP)))
+ goto free;
+
+ /*
+ * Validate source addresses
+ * can't be from broadcast
+ * can't be from me
+ */
+ if (!spans_addr_cmp(&ahp->ah_sha, &spans_bcastaddr))
+ goto free;
+#if (defined(BSD) && (BSD >= 199306))
+ if (in_broadcast(in_src, &inp->inf_nif->nif_if))
+#else
+ if (in_broadcast(in_src))
+#endif
+ goto free;
+ if (!spans_addr_cmp(&ahp->ah_sha, spp->sp_addr.address))
+ goto free;
+ if (in_src.s_addr == in_me.s_addr) {
+ log(LOG_ERR,
+ "duplicate IP address sent from spans address %s\n",
+ spans_addr_print(&ahp->ah_sha));
+ in_targ = in_me;
+ goto chkop;
+ }
+
+ /*
+ * Update arp table with source address info
+ */
+ s = splnet();
+ SPANSARP_LOOKUP(in_src.s_addr, sap);
+ if (sap) {
+ /*
+ * Found an entry for the source, but don't
+ * update permanent entries
+ */
+ if (sap->sa_origin != SAO_PERM) {
+
+ /*
+ * Update the entry
+ */
+ sap->sa_dstatm.address_format = T_ATM_SPANS_ADDR;
+ sap->sa_dstatm.address_length = sizeof(spans_addr);
+ spans_addr_copy(&ahp->ah_sha, sap->sa_dstatm.address);
+ sap->sa_cls = clp;
+ sap->sa_reftime = 0;
+ if ((sap->sa_flags & SAF_VALID) == 0) {
+ /*
+ * Newly valid entry, notify waiting users
+ */
+ struct ipvcc *ivp, *inext;
+
+ sap->sa_flags |= SAF_VALID;
+ for (ivp = sap->sa_ivp; ivp; ivp = inext) {
+ inext = ivp->iv_arpnext;
+
+ ivp->iv_arpent = (struct arpmap *)sap;
+ (*inp->inf_arpnotify)(ivp, MAP_VALID);
+ }
+
+ /*
+ * Remove ourselves from the retry chain
+ */
+ UNLINK(sap, struct spansarp,
+ spansarp_retry_head, sa_rnext);
+ }
+ }
+
+ } else if (in_targ.s_addr == in_me.s_addr) {
+ /*
+ * Source unknown and we're the target - add new entry
+ */
+ sap = (struct spansarp *)atm_allocate(&spansarp_pool);
+ if (sap) {
+ sap->sa_dstip.s_addr = in_src.s_addr;
+ sap->sa_dstatm.address_format = T_ATM_SPANS_ADDR;
+ sap->sa_dstatm.address_length = sizeof(spans_addr);
+ spans_addr_copy(&ahp->ah_sha, sap->sa_dstatm.address);
+ sap->sa_dstatmsub.address_format = T_ATM_ABSENT;
+ sap->sa_dstatmsub.address_length = 0;
+ sap->sa_cls = clp;
+ sap->sa_flags = SAF_VALID;
+ sap->sa_origin = SAO_LOOKUP;
+ SPANSARP_ADD(sap);
+ }
+ }
+ (void) splx(s);
+
+chkop:
+ /*
+ * If this is a request for our address, send a reply
+ */
+ if (ntohs(ahp->ah_op) != ARP_REQUEST)
+ goto free;
+ if (in_targ.s_addr != in_me.s_addr)
+ goto free;
+
+ spans_addr_copy(&chp->ch_src, &chp->ch_dst);
+ spans_addr_copy(spp->sp_addr.address, &chp->ch_src);
+ ahp->ah_op = htons(ARP_REPLY);
+ spans_addr_copy(&ahp->ah_sha, &ahp->ah_tha);
+ spans_addr_copy(spp->sp_addr.address, &ahp->ah_sha);
+ KM_COPY(ahp->ah_spa, ahp->ah_tpa, sizeof(struct in_addr));
+ KM_COPY(&in_me, ahp->ah_spa, sizeof(struct in_addr));
+
+ err = atm_cm_cpcs_data(clp->cls_conn, m);
+ if (err)
+ goto free;
+ return;
+
+free:
+ KB_FREEALL(m);
+}
+
+
+/*
+ * Process a SPANS ARP aging timer tick
+ *
+ * This function is called every SPANSARP_AGING seconds, in order to age
+ * all the arp table entries.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * tip pointer to spansarp aging timer control block
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+spansarp_aging(tip)
+ struct atm_time *tip;
+{
+ struct spansarp *sap, *snext;
+ struct ipvcc *ivp, *inext;
+ int i;
+
+
+ /*
+ * Schedule next timeout
+ */
+ atm_timeout(&spansarp_timer, SPANSARP_AGING, spansarp_aging);
+
+ /*
+ * Run through arp table bumping each entry's aging timer.
+ */
+ for (i = 0; i < SPANSARP_HASHSIZ; i++) {
+ for (sap = spansarp_arptab[i]; sap; sap = snext) {
+ snext = sap->sa_next;
+
+ /*
+ * Permanent (manually installed) entries aren't aged
+ */
+ if (sap->sa_origin == SAO_PERM)
+ continue;
+
+ /*
+ * See if entry is valid and over-aged
+ */
+ if ((sap->sa_flags & SAF_VALID) == 0)
+ continue;
+ if (++sap->sa_reftime < SPANSARP_MAXAGE)
+ continue;
+
+ /*
+ * Entry is now invalid, tell IP/ATM about it
+ */
+ sap->sa_flags |= SAF_LOCKED;
+ for (ivp = sap->sa_ivp; ivp; ivp = inext) {
+ inext = ivp->iv_arpnext;
+ (*ivp->iv_ipnif->inf_arpnotify)
+ (ivp, MAP_INVALID);
+ }
+ sap->sa_flags &= ~(SAF_LOCKED | SAF_VALID);
+
+ if (sap->sa_ivp != NULL) {
+ /*
+ * Somebody still cares, so add the arp
+ * entry to the retry list.
+ */
+ LINK2TAIL(sap, struct spansarp,
+ spansarp_retry_head, sa_rnext);
+ if ((spansarp_rtimer.ti_flag & TIF_QUEUED) == 0)
+ atm_timeout(&spansarp_rtimer,
+ SPANSARP_RETRY, spansarp_retry);
+
+ /*
+ * Issue arp request for this address
+ */
+ (void) spansarp_request(sap);
+
+ } else {
+ /*
+ * Delete unused entry
+ */
+ SPANSARP_DELETE(sap);
+ atm_free((caddr_t)sap);
+ }
+ }
+ }
+}
+
+
+/*
+ * Process a SPANS ARP retry timer tick
+ *
+ * This function is called every SPANSARP_RETRY seconds, in order to retry
+ * awaiting arp resolution requests. We will retry requests indefinitely,
+ * assuming that IP will set a timeout to close the VCC(s) requesting the
+ * failing address resolution.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * tip pointer to spansarp retry timer control block
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+spansarp_retry(tip)
+ struct atm_time *tip;
+{
+ struct spansarp *sap;
+
+
+ /*
+ * See if there's work to do
+ */
+ if (spansarp_retry_head == NULL) {
+ return;
+ }
+
+ /*
+ * Schedule next timeout
+ */
+ atm_timeout(&spansarp_rtimer, SPANSARP_RETRY, spansarp_retry);
+
+ /*
+ * Run through retry chain, (re)issuing arp requests.
+ */
+ for (sap = spansarp_retry_head; sap; sap = sap->sa_next) {
+
+ /*
+ * Send another arp request
+ */
+ (void) spansarp_request(sap);
+ }
+}
+
+
+/*
+ * SPANS ARP IOCTL support
+ *
+ * Function will be called at splnet.
+ *
+ * Arguments:
+ * code PF_ATM sub-operation code
+ * data pointer to code specific parameter data area
+ * arg1 pointer to code specific argument
+ *
+ * Returns:
+ * 0 request procesed
+ * errno error processing request - reason indicated
+ *
+ */
+int
+spansarp_ioctl(code, data, arg1)
+ int code;
+ caddr_t data;
+ caddr_t arg1;
+{
+ struct atmaddreq *aap;
+ struct atmdelreq *adp;
+ struct atminfreq *aip;
+ struct spans *spp;
+ struct spanscls *clp;
+ struct spansarp *sap;
+ struct air_arp_rsp aar;
+ struct ip_nif *inp;
+ struct ipvcc *ivp, *inext;
+ struct in_addr ip;
+ u_long dst;
+ int err = 0, i, buf_len;
+ caddr_t buf_addr;
+
+
+ switch (code) {
+
+ case AIOCS_ADD_ARP:
+ /*
+ * Add a permanent ARP mapping
+ */
+ aap = (struct atmaddreq *)data;
+ clp = (struct spanscls *)arg1;
+ inp = clp->cls_ipnif;
+ if ((aap->aar_arp_addr.address_format != T_ATM_SPANS_ADDR) ||
+ (aap->aar_arp_origin != ARP_ORIG_PERM)) {
+ err = EINVAL;
+ break;
+ }
+ ip = SATOSIN(&aap->aar_arp_dst)->sin_addr;
+
+ /*
+ * See if we already have an entry for this IP address
+ */
+ SPANSARP_LOOKUP(ip.s_addr, sap);
+ if (sap == NULL) {
+ /*
+ * No, get a new arp entry
+ */
+ sap = (struct spansarp *)atm_allocate(&spansarp_pool);
+ if (sap == NULL) {
+ err = ENOMEM;
+ break;
+ }
+
+ /*
+ * Get entry set up
+ */
+ sap->sa_dstip = ip;
+ ATM_ADDR_COPY(&aap->aar_arp_addr, &sap->sa_dstatm);
+ sap->sa_dstatmsub.address_format = T_ATM_ABSENT;
+ sap->sa_dstatmsub.address_length = 0;
+ sap->sa_cls = clp;
+ sap->sa_flags |= SAF_VALID;
+ sap->sa_origin = SAO_PERM;
+
+ /*
+ * Add entry to table
+ */
+ SPANSARP_ADD(sap);
+ break;
+
+ }
+
+ /*
+ * See if we're attempting to change the ATM address for
+ * this cached entry
+ */
+ if ((sap->sa_dstatm.address_format != T_ATM_ABSENT) &&
+ (!ATM_ADDR_EQUAL(&aap->aar_arp_addr, &sap->sa_dstatm) ||
+ (clp != sap->sa_cls))) {
+
+ /*
+ * Yes, notify IP/ATM that a mapping change has
+ * occurred. IP/ATM will close any VCC's which
+ * aren't waiting for this map.
+ */
+ sap->sa_flags |= SAF_LOCKED;
+ for (ivp = sap->sa_ivp; ivp; ivp = inext) {
+ inext = ivp->iv_arpnext;
+ (*inp->inf_arpnotify)(ivp, MAP_CHANGED);
+ }
+ sap->sa_flags &= ~SAF_LOCKED;
+ }
+
+ /*
+ * Update the cached entry with the new data
+ */
+ ATM_ADDR_COPY(&aap->aar_arp_addr, &sap->sa_dstatm);
+ sap->sa_cls = clp;
+
+ /*
+ * If this entry isn't valid, notify anyone who might
+ * be interested
+ */
+ if ((sap->sa_flags & SAF_VALID) == 0) {
+
+ sap->sa_flags |= SAF_LOCKED;
+ for (ivp = sap->sa_ivp; ivp; ivp = inext) {
+ inext = ivp->iv_arpnext;
+ (*inp->inf_arpnotify)(ivp, MAP_VALID);
+ }
+ sap->sa_flags &= ~SAF_LOCKED;
+ }
+
+ /*
+ * Remove this entry from the retry chain
+ */
+ UNLINK(sap, struct spansarp, spansarp_retry_head, sa_rnext);
+
+ /*
+ * Mark the entry as permanent
+ */
+ sap->sa_flags |= SAF_VALID;
+ sap->sa_origin = SAO_PERM;
+ break;
+
+ case AIOCS_DEL_ARP:
+ /*
+ * Delete an ARP mapping
+ */
+ adp = (struct atmdelreq *)data;
+ clp = (struct spanscls *)arg1;
+ ip = SATOSIN(&adp->adr_arp_dst)->sin_addr;
+
+ /*
+ * Now find the entry to be deleted
+ */
+ SPANSARP_LOOKUP(ip.s_addr, sap);
+ if (sap == NULL) {
+ err = ENOENT;
+ break;
+ }
+
+ /*
+ * Notify all VCCs using this entry that they must finish
+ * up now.
+ */
+ sap->sa_flags |= SAF_LOCKED;
+ for (ivp = sap->sa_ivp; ivp; ivp = inext) {
+ inext = ivp->iv_arpnext;
+ (*ivp->iv_ipnif->inf_arpnotify)(ivp, MAP_FAILED);
+ }
+
+ /*
+ * Now free up the entry
+ */
+ UNLINK(sap, struct spansarp, spansarp_retry_head, sa_rnext);
+ SPANSARP_DELETE(sap);
+ atm_free((caddr_t)sap);
+ break;
+
+ case AIOCS_INF_ARP:
+ /*
+ * Get ARP table information
+ */
+ aip = (struct atminfreq *)data;
+ spp = (struct spans *)arg1;
+
+ if (aip->air_arp_addr.sa_family != AF_INET)
+ break;
+ dst = SATOSIN(&aip->air_arp_addr)->sin_addr.s_addr;
+
+ buf_addr = aip->air_buf_addr;
+ buf_len = aip->air_buf_len;
+
+ if ((clp = spp->sp_cls) == NULL)
+ break;
+
+ /*
+ * Run through entire arp table
+ */
+ for (i = 0; i < SPANSARP_HASHSIZ; i++) {
+ for (sap = spansarp_arptab[i]; sap;
+ sap = sap->sa_next) {
+ /*
+ * We only want entries learned
+ * from the supplied interface.
+ */
+ if (sap->sa_cls != clp)
+ continue;
+ if ((dst != INADDR_ANY) &&
+ (dst != sap->sa_dstip.s_addr))
+ continue;
+
+ /*
+ * Make sure there's room in the user's buffer
+ */
+ if (buf_len < sizeof(aar)) {
+ err = ENOSPC;
+ break;
+ }
+
+ /*
+ * Fill in info to be returned
+ */
+ SATOSIN(&aar.aap_arp_addr)->sin_family =
+ AF_INET;
+ SATOSIN(&aar.aap_arp_addr)->sin_addr.s_addr =
+ sap->sa_dstip.s_addr;
+ (void) sprintf(aar.aap_intf, "%s%d",
+ clp->cls_ipnif->inf_nif->nif_if.if_name,
+ clp->cls_ipnif->inf_nif->nif_if.if_unit
+ );
+ aar.aap_flags = sap->sa_flags;
+ aar.aap_origin = sap->sa_origin;
+ if (sap->sa_flags & SAF_VALID)
+ aar.aap_age = SPANSARP_MAXAGE -
+ sap->sa_reftime;
+ else
+ aar.aap_age = 0;
+ ATM_ADDR_COPY(&sap->sa_dstatm, &aar.aap_addr);
+ ATM_ADDR_COPY(&sap->sa_dstatmsub,
+ &aar.aap_subaddr);
+
+ /*
+ * Copy the response into the user's buffer
+ */
+ if (err = copyout((caddr_t)&aar, buf_addr,
+ sizeof(aar)))
+ break;
+ buf_addr += sizeof(aar);
+ buf_len -= sizeof(aar);
+ }
+ if (err)
+ break;
+ }
+
+ /*
+ * Update the buffer pointer and length
+ */
+ aip->air_buf_addr = buf_addr;
+ aip->air_buf_len = buf_len;
+ break;
+
+ default:
+ err = EOPNOTSUPP;
+ }
+
+ return (err);
+}
+
diff --git a/sys/netatm/spans/spans_cls.c b/sys/netatm/spans/spans_cls.c
new file mode 100644
index 0000000..f496311
--- /dev/null
+++ b/sys/netatm/spans/spans_cls.c
@@ -0,0 +1,848 @@
+/*
+ *
+ * ===================================
+ * 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: spans_cls.c,v 1.11 1998/06/29 22:04:29 mks Exp $
+ *
+ */
+
+/*
+ * SPANS Signalling Manager
+ * ---------------------------
+ *
+ * SPANS Connectionless Datagram Service (CLS) module
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: spans_cls.c,v 1.11 1998/06/29 22:04:29 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/ipatm/ipatm_var.h>
+#include <netatm/ipatm/ipatm_serv.h>
+#include "spans_xdr.h"
+#include <netatm/spans/spans_var.h>
+#include <netatm/spans/spans_cls.h>
+
+
+/*
+ * Global variables
+ */
+int spanscls_print = 0;
+
+struct spanscls *spanscls_head = NULL;
+
+struct spans_addr spans_bcastaddr = {
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
+};
+
+struct spanscls_hdr spanscls_hdr = {
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* dst */
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* src */
+ 0x00, 0x00, 0,
+ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0 /* LLC SNAP */
+};
+
+
+/*
+ * Local functions
+ */
+static int spanscls_ipact __P((struct ip_nif *));
+static int spanscls_ipdact __P((struct ip_nif *));
+static int spanscls_bcast_output __P((struct ip_nif *, KBuffer *));
+static void spanscls_cpcs_data __P((void *, KBuffer *));
+static void spanscls_connected __P((void *));
+static void spanscls_cleared __P((void *, struct t_atm_cause *));
+static caddr_t spanscls_getname __P((void *));
+static void spanscls_pdu_print __P((struct spanscls *, KBuffer *,
+ char *));
+
+/*
+ * Local variables
+ */
+static struct sp_info spanscls_pool = {
+ "spans cls pool", /* si_name */
+ sizeof(struct spanscls), /* si_blksiz */
+ 2, /* si_blkcnt */
+ 100 /* si_maxallow */
+};
+
+static struct ip_serv spanscls_ipserv = {
+ spanscls_ipact,
+ spanscls_ipdact,
+ spansarp_ioctl,
+ NULL,
+ spansarp_svcout,
+ spansarp_svcin,
+ spansarp_svcactive,
+ spansarp_vcclose,
+ spanscls_bcast_output,
+ {
+ {ATM_AAL5, ATM_ENC_NULL},
+ {ATM_AAL3_4, ATM_ENC_NULL}
+ }
+};
+
+static u_char spanscls_bridged[] = {
+ 0x00, 0x00, 0x00, 0x00,
+ 0xaa, 0xaa, 0x03, 0x00, 0x80, 0xc2 /* LLC SNAP */
+};
+
+static Atm_endpoint spanscls_endpt = {
+ NULL,
+ ENDPT_SPANS_CLS,
+ NULL,
+ spanscls_getname,
+ spanscls_connected,
+ spanscls_cleared,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ spanscls_cpcs_data,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+static Atm_attributes spanscls_attr = {
+ NULL, /* nif */
+ CMAPI_CPCS, /* api */
+ 0, /* api_init */
+ 0, /* headin */
+ 0, /* headout */
+ { /* aal */
+ T_ATM_PRESENT,
+ ATM_AAL3_4
+ },
+ { /* traffic */
+ T_ATM_PRESENT,
+ {
+ {
+ T_ATM_ABSENT,
+ 0,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_NO
+ },
+ {
+ T_ATM_ABSENT,
+ 0,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_NO
+ },
+ T_YES
+ },
+ },
+ { /* bearer */
+ T_ATM_PRESENT,
+ {
+ T_ATM_CLASS_X,
+ T_ATM_NULL,
+ T_ATM_NULL,
+ T_NO,
+ T_ATM_1_TO_1
+ }
+ },
+ { /* bhli */
+ T_ATM_ABSENT
+ },
+ { /* blli */
+ T_ATM_ABSENT,
+ T_ATM_ABSENT
+ },
+ { /* llc */
+ T_ATM_ABSENT
+ },
+ { /* called */
+ T_ATM_PRESENT,
+ },
+ { /* calling */
+ T_ATM_ABSENT
+ },
+ { /* qos */
+ T_ATM_PRESENT,
+ {
+ T_ATM_NETWORK_CODING,
+ {
+ T_ATM_QOS_CLASS_0,
+ },
+ {
+ T_ATM_QOS_CLASS_0
+ }
+ }
+ },
+ { /* transit */
+ T_ATM_ABSENT
+ },
+ { /* cause */
+ T_ATM_ABSENT
+ }
+};
+
+static struct t_atm_cause spanscls_cause = {
+ T_ATM_ITU_CODING,
+ T_ATM_LOC_USER,
+ T_ATM_CAUSE_UNSPECIFIED_NORMAL,
+ {0, 0, 0, 0}
+};
+
+
+/*
+ * Process module loading
+ *
+ * Called whenever the spans module is initializing.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 initialization successful
+ * errno initialization failed - reason indicated
+ *
+ */
+int
+spanscls_start()
+{
+ int err;
+
+ /*
+ * Fill in union fields
+ */
+ spanscls_attr.aal.v.aal4.forward_max_SDU_size = ATM_NIF_MTU;
+ spanscls_attr.aal.v.aal4.backward_max_SDU_size = ATM_NIF_MTU;
+ spanscls_attr.aal.v.aal4.SSCS_type = T_ATM_NULL;
+ spanscls_attr.aal.v.aal4.mid_low = 0;
+ spanscls_attr.aal.v.aal4.mid_high = 1023;
+
+ /*
+ * Register our endpoint
+ */
+ err = atm_endpoint_register(&spanscls_endpt);
+
+ return (err);
+}
+
+
+/*
+ * Process module unloading notification
+ *
+ * Called whenever the spans module is about to be unloaded. All signalling
+ * instances will have been previously detached. All spanscls resources
+ * must be freed now.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+spanscls_stop()
+{
+ int s = splnet();
+
+ /*
+ * Tell ARP to stop
+ */
+ spansarp_stop();
+
+ /*
+ * Nothing should be left here...
+ */
+ if (spanscls_head) {
+ panic("spanscls_stop: bad state");
+ }
+ (void) splx(s);
+
+ /*
+ * De-register ourselves
+ */
+ (void) atm_endpoint_deregister(&spanscls_endpt);
+
+ /*
+ * Free our storage pools
+ */
+ atm_release_pool(&spanscls_pool);
+}
+
+
+/*
+ * Process signalling interface attach
+ *
+ * This function is called whenever a physical interface has been attached
+ * to spans. We will open the CLS PVC and await further events.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * spp pointer to spans signalling protocol instance
+ *
+ * Returns:
+ * 0 attach successful
+ * errno attach failed - reason indicated
+ *
+ */
+int
+spanscls_attach(spp)
+ struct spans *spp;
+{
+ struct spanscls *clp;
+ Atm_addr_pvc *pvcp;
+ int err;
+
+ /*
+ * Get a new cls control block
+ */
+ clp = (struct spanscls *)atm_allocate(&spanscls_pool);
+ if (clp == NULL)
+ return (ENOMEM);
+
+ /*
+ * Initialize some stuff
+ */
+ clp->cls_state = CLS_CLOSED;
+ clp->cls_spans = spp;
+ spp->sp_ipserv = &spanscls_ipserv;
+
+ /*
+ * Fill out connection attributes
+ */
+ spanscls_attr.nif = spp->sp_pif->pif_nif;
+ spanscls_attr.traffic.v.forward.PCR_all_traffic = spp->sp_pif->pif_pcr;
+ spanscls_attr.traffic.v.backward.PCR_all_traffic = spp->sp_pif->pif_pcr;
+ spanscls_attr.called.addr.address_format = T_ATM_PVC_ADDR;
+ spanscls_attr.called.addr.address_length = sizeof(Atm_addr_pvc);
+ pvcp = (Atm_addr_pvc *)spanscls_attr.called.addr.address;
+ ATM_PVC_SET_VPI(pvcp, SPANS_CLS_VPI);
+ ATM_PVC_SET_VCI(pvcp, SPANS_CLS_VCI);
+ spanscls_attr.called.subaddr.address_format = T_ATM_ABSENT;
+ spanscls_attr.called.subaddr.address_length = 0;
+
+ /*
+ * Create SPANS Connectionless Service (CLS) PVC
+ */
+ err = atm_cm_connect(&spanscls_endpt, clp, &spanscls_attr,
+ &clp->cls_conn);
+ if (err) {
+ atm_free((caddr_t)clp);
+ return (err);
+ }
+
+ /*
+ * Set new state and link instance
+ */
+ clp->cls_state = CLS_OPEN;
+ LINK2TAIL(clp, struct spanscls, spanscls_head, cls_next);
+ spp->sp_cls = clp;
+
+ return (0);
+}
+
+
+/*
+ * Process signalling interface detach
+ *
+ * This function is called whenever a physical interface has been detached
+ * from spans. We will close the CLS PVC and clean up everything.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * spp pointer to spans signalling protocol instance
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+spanscls_detach(spp)
+ struct spans *spp;
+{
+ struct spanscls *clp;
+
+ /*
+ * Get our control block
+ */
+ clp = spp->sp_cls;
+ if (clp == NULL)
+ return;
+
+ /*
+ * Just checking up on things...
+ */
+ if (clp->cls_ipnif)
+ panic("spanscls_detach: IP interface still active");
+
+ /*
+ * Close CLS PVC
+ */
+ spanscls_closevc(clp, &spanscls_cause);
+
+ /*
+ * Sever links and free server block, if possible
+ */
+ clp->cls_spans = NULL;
+ spp->sp_cls = NULL;
+ if (clp->cls_state == CLS_CLOSED) {
+ UNLINK(clp, struct spanscls, spanscls_head, cls_next);
+ atm_free((caddr_t)clp);
+ }
+}
+
+
+/*
+ * Process IP Network Interface Activation
+ *
+ * Called whenever an IP network interface becomes active.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * inp pointer to IP network interface
+ *
+ * Returns:
+ * 0 command successful
+ * errno command failed - reason indicated
+ *
+ */
+static int
+spanscls_ipact(inp)
+ struct ip_nif *inp;
+{
+ struct spans *spp;
+ struct spanscls *clp;
+
+ /*
+ * Get corresponding cls instance
+ */
+ spp = (struct spans *)inp->inf_nif->nif_pif->pif_siginst;
+ if ((spp == NULL) || ((clp = spp->sp_cls) == NULL))
+ return (ENXIO);
+
+ /*
+ * Make sure it's not already activated
+ */
+ if (clp->cls_ipnif)
+ return (EEXIST);
+
+ /*
+ * Set two-way links with IP world
+ */
+ clp->cls_ipnif = inp;
+ inp->inf_isintf = (caddr_t)clp;
+
+ /*
+ * Tell arp about new interface
+ */
+ spansarp_ipact(clp);
+
+ return (0);
+}
+
+
+/*
+ * Process IP Network Interface Deactivation
+ *
+ * Called whenever an IP network interface becomes inactive.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * inp pointer to IP network interface
+ *
+ * Returns:
+ * 0 command successful
+ * errno command failed - reason indicated
+ *
+ */
+static int
+spanscls_ipdact(inp)
+ struct ip_nif *inp;
+{
+ struct spanscls *clp;
+
+ /*
+ * Get cls instance and make sure it's been activated
+ */
+ clp = (struct spanscls *)inp->inf_isintf;
+ if ((clp == NULL) || (clp->cls_ipnif == NULL))
+ return (ENXIO);
+
+ /*
+ * Let arp know about this
+ */
+ spansarp_ipdact(clp);
+
+ /*
+ * Clear IP interface pointer
+ */
+ clp->cls_ipnif = NULL;
+ return (0);
+}
+
+
+/*
+ * Output IP Broadcast Packet
+ *
+ * Called whenever an IP broadcast packet is sent to this interface.
+ *
+ * Arguments:
+ * inp pointer to IP network interface
+ * m pointer to packet buffer chain
+ *
+ * Returns:
+ * 0 packet sent successfully
+ * errno send failed - reason indicated
+ *
+ */
+static int
+spanscls_bcast_output(inp, m)
+ struct ip_nif *inp;
+ KBuffer *m;
+{
+ struct spans *spp;
+ struct spanscls *clp;
+ struct spanscls_hdr *chp;
+ int err, space;
+
+ /*
+ * Get cls instance and make sure it's been activated
+ */
+ clp = (struct spanscls *)inp->inf_isintf;
+ if ((clp == NULL) || (clp->cls_ipnif == NULL)) {
+ KB_FREEALL(m);
+ return (ENETDOWN);
+ }
+
+ /*
+ * Make sure that we know our addresses
+ */
+ spp = clp->cls_spans;
+ if (spp->sp_addr.address_format != T_ATM_SPANS_ADDR) {
+ KB_FREEALL(m);
+ return (ENETDOWN);
+ }
+
+ /*
+ * See if there's room to add CLS header to front of packet.
+ */
+ KB_HEADROOM(m, space);
+ if (space < sizeof(struct spanscls_hdr)) {
+ KBuffer *n;
+
+ /*
+ * We have to allocate another buffer and tack it
+ * onto the front of the packet
+ */
+ KB_ALLOCPKT(n, sizeof(struct spanscls_hdr),
+ KB_F_NOWAIT, KB_T_HEADER);
+ if (n == 0) {
+ KB_FREEALL(m);
+ return (ENOBUFS);
+ }
+ KB_TAILALIGN(n, sizeof(struct spanscls_hdr));
+ KB_LINKHEAD(n, m);
+ m = n;
+ } else {
+ /*
+ * Header fits, just adjust buffer controls
+ */
+ KB_HEADADJ(m, sizeof(struct spanscls_hdr));
+ }
+
+ /*
+ * Now, build the CLS header
+ */
+ KB_DATASTART(m, chp, struct spanscls_hdr *);
+ spans_addr_copy(&spans_bcastaddr, &chp->ch_dst);
+ spans_addr_copy(spp->sp_addr.address, &chp->ch_src);
+ *(u_int *)&chp->ch_proto = *(u_int *)&spanscls_hdr.ch_proto;
+ *(u_int *)&chp->ch_dsap = *(u_int *)&spanscls_hdr.ch_dsap;
+ *(u_short *)&chp->ch_oui[1] = *(u_short *)&spanscls_hdr.ch_oui[1];
+ chp->ch_pid = htons(ETHERTYPE_IP);
+
+#ifdef DIAGNOSTIC
+ if (spanscls_print)
+ spanscls_pdu_print(clp, m, "output");
+#endif
+
+ /*
+ * Finally, send the pdu via the CLS service
+ */
+ err = atm_cm_cpcs_data(clp->cls_conn, m);
+ if (err) {
+ KB_FREEALL(m);
+ return (ENOBUFS);
+ }
+
+ return (0);
+}
+
+
+/*
+ * Process VCC Input Data
+ *
+ * All input packets received from CLS VCC lower layers are processed here.
+ *
+ * Arguments:
+ * tok connection token (pointer to CLS VCC control block)
+ * m pointer to input packet buffer chain
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+spanscls_cpcs_data(tok, m)
+ void *tok;
+ KBuffer *m;
+{
+ struct spanscls *clp = tok;
+ struct spans *spp = clp->cls_spans;
+ struct spanscls_hdr *chp;
+ struct ip_nif *inp;
+
+ /*
+ * Make sure we're ready
+ */
+ if ((clp->cls_state != CLS_OPEN) || (spp->sp_state != SPANS_ACTIVE)) {
+ KB_FREEALL(m);
+ return;
+ }
+
+#ifdef DIAGNOSTIC
+ if (spanscls_print)
+ spanscls_pdu_print(clp, m, "input");
+#endif
+
+ /*
+ * Get CLS header into buffer
+ */
+ if (KB_LEN(m) < sizeof(struct spanscls_hdr)) {
+ KB_PULLUP(m, sizeof(struct spanscls_hdr), m);
+ if (m == 0)
+ return;
+ }
+ KB_DATASTART(m, chp, struct spanscls_hdr *);
+
+ /*
+ * Verify packet information
+ */
+ if ((*(u_int *)&chp->ch_proto != *(u_int *)&spanscls_hdr.ch_proto) ||
+ (*(u_int *)&chp->ch_dsap != *(u_int *)&spanscls_hdr.ch_dsap) ||
+ (*(u_short *)&chp->ch_oui[1] !=
+ *(u_short *)&spanscls_hdr.ch_oui[1])) {
+
+ /*
+ * Check for bridged PDU
+ */
+ if (bcmp((char *)&chp->ch_proto, (char *)spanscls_bridged,
+ sizeof(spanscls_bridged))) {
+ log(LOG_ERR, "spanscls_input: bad format\n");
+#ifdef DIAGNOSTIC
+ spanscls_pdu_print(clp, m, "input error");
+#endif
+ }
+
+ KB_FREEALL(m);
+ return;
+ }
+
+ /*
+ * Make sure packet is for us
+ */
+ if (spans_addr_cmp(&chp->ch_dst, spp->sp_addr.address) &&
+ spans_addr_cmp(&chp->ch_dst, &spans_bcastaddr)) {
+ KB_FREEALL(m);
+ return;
+ }
+
+ /*
+ * Do protocol processing
+ */
+ switch (ntohs(chp->ch_pid)) {
+
+ case ETHERTYPE_IP:
+ /*
+ * Drop CLS header
+ */
+ KB_HEADADJ(m, -sizeof(struct spanscls_hdr));
+ KB_PLENADJ(m, -sizeof(struct spanscls_hdr));
+
+ /*
+ * Packet is ready for input to IP
+ */
+ if (inp = clp->cls_ipnif)
+ (void) (*inp->inf_ipinput)(inp, m);
+ else
+ KB_FREEALL(m);
+ break;
+
+ case ETHERTYPE_ARP:
+ spansarp_input(clp, m);
+ break;
+
+ default:
+ log(LOG_ERR, "spanscls_input: unknown protocol 0x%x\n",
+ chp->ch_pid);
+ KB_FREEALL(m);
+ return;
+ }
+}
+
+
+/*
+ * Close a SPANS CLS VCC
+ *
+ * This function will close a SPANS CLS VCC.
+ *
+ * Arguments:
+ * clp pointer to CLS instance
+ * cause pointer to cause code
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+spanscls_closevc(clp, cause)
+ struct spanscls *clp;
+ struct t_atm_cause *cause;
+{
+ int err;
+
+ /*
+ * Close VCC
+ */
+ if (clp->cls_conn) {
+ err = atm_cm_release(clp->cls_conn, cause);
+ if (err) {
+ log(LOG_ERR, "spanscls_closevc: release err=%d\n", err);
+ }
+ clp->cls_conn = NULL;
+ }
+
+ clp->cls_state = CLS_CLOSED;
+}
+
+
+/*
+ * Process CLS VCC Connected Notification
+ *
+ * Arguments:
+ * toku user's connection token (spanscls protocol block)
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+spanscls_connected(toku)
+ void *toku;
+{
+ /*
+ * We should never get one of these
+ */
+ log(LOG_ERR, "spanscls: unexpected connected event\n");
+}
+
+
+/*
+ * Process CLS VCC Cleared Notification
+ *
+ * Arguments:
+ * toku user's connection token (spanscls protocol block)
+ * cause pointer to cause code
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+spanscls_cleared(toku, cause)
+ void *toku;
+ struct t_atm_cause *cause;
+{
+ struct spanscls *clp = (struct spanscls *)toku;
+
+ /*
+ * CLS VCC has been closed, so clean up our side
+ */
+ clp->cls_conn = NULL;
+ spanscls_closevc(clp, cause);
+}
+
+
+/*
+ * Get Connection's Application/Owner Name
+ *
+ * Arguments:
+ * tok spanscls connection token
+ *
+ * Returns:
+ * addr pointer to string containing our name
+ *
+ */
+static caddr_t
+spanscls_getname(tok)
+ void *tok;
+{
+ return ("SPANSCLS");
+}
+
+
+/*
+ * Print a SPANS CLS PDU
+ *
+ * Arguments:
+ * clp pointer to cls instance
+ * m pointer to pdu buffer chain
+ * msg pointer to message string
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+spanscls_pdu_print(clp, m, msg)
+ struct spanscls *clp;
+ KBuffer *m;
+ char *msg;
+{
+ char buf[128];
+
+ sprintf(buf, "spanscls %s:\n", msg);
+ atm_pdu_print(m, buf);
+}
+
diff --git a/sys/netatm/spans/spans_cls.h b/sys/netatm/spans/spans_cls.h
new file mode 100644
index 0000000..d2cacac
--- /dev/null
+++ b/sys/netatm/spans/spans_cls.h
@@ -0,0 +1,188 @@
+/*
+ *
+ * ===================================
+ * 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: spans_cls.h,v 1.6 1998/05/18 19:11:17 mks Exp $
+ *
+ */
+
+/*
+ * SPANS Signalling Manager
+ * ---------------------------
+ *
+ * SPANS Connectionless Datagram Service (CLS) control blocks
+ *
+ */
+
+#ifndef _SPANS_SPANSCLS_H
+#define _SPANS_SPANSCLS_H
+
+/*
+ * Protocol constants
+ */
+#define SPANSARP_AGING (60 * ATM_HZ) /* ARP aging timer */
+#define SPANSARP_RETRY (3 * ATM_HZ) /* ARP retry timer */
+#define SPANSARP_MAXAGE 20 /* Max ARP entry age (minutes)*/
+#define SPANSARP_HASHSIZ 19 /* Hash table size */
+
+
+/*
+ * SPANS CLS protocol structure. There will be one such structure for
+ * each SPANS signalling instance.
+ */
+struct spanscls {
+ struct spanscls *cls_next; /* Next attached cls instance */
+ u_char cls_state; /* Protocol state (see below) */
+ struct spans *cls_spans; /* Spans signalling instance */
+ Atm_connection *cls_conn; /* Connection manager token */
+ struct ip_nif *cls_ipnif; /* IP network interface */
+};
+
+/*
+ * SPANS CLS Protocol States
+ */
+#define CLS_CLOSED 1 /* CLS PVC is closed */
+#define CLS_OPEN 2 /* CLS PVC is open */
+
+
+/*
+ * Structure for SPANS ARP mappings. Each of these structures will contain
+ * IP address to SPANS hardware address mappings. There will be one such
+ * structure for each IP address currently in use.
+ */
+struct spansarp {
+ struct arpmap sa_arpmap; /* Common entry header */
+ struct spanscls *sa_cls; /* Interface where we learned answer */
+ struct spansarp *sa_next; /* Hash chain */
+ struct spansarp *sa_rnext; /* Retry chain */
+ u_char sa_flags; /* Flags (see below) */
+ u_char sa_origin; /* Origin (see below) */
+ u_short sa_reftime; /* Entry reference time (minutes) */
+ struct ipvcc *sa_ivp; /* IP VCCs waiting for answer */
+};
+#define sa_dstip sa_arpmap.am_dstip
+#define sa_dstatm sa_arpmap.am_dstatm
+#define sa_dstatmsub sa_arpmap.am_dstatmsub
+
+/*
+ * Entry Flags
+ */
+#define SAF_VALID ARPF_VALID /* Entry is valid */
+#define SAF_REFRESH ARPF_REFRESH /* Entry has been refreshed */
+#define SAF_LOCKED 0x04 /* Entry is locked */
+
+/*
+ * Entry Origin
+ */
+#define SAO_PERM ARP_ORIG_PERM /* Entry is permanently installed */
+#define SAO_LOOKUP 20 /* Learned via lookup */
+
+
+/*
+ * SPANS CLS Packet Header
+ */
+struct spanscls_hdr {
+ /* IEEE 802.6 MAC header */
+ spans_addr ch_dst; /* Destination SPANS address */
+ spans_addr ch_src; /* Source SPANS address */
+ u_char ch_proto; /* */
+ u_char ch_extlen; /* */
+ u_short ch_bridging; /* */
+
+ /* LLC SNAP header */
+ u_char ch_dsap; /* Destination SAP */
+ u_char ch_ssap; /* Source SAP */
+ u_char ch_ctl; /* Control field */
+ u_char ch_oui[3]; /* Organizationally Unique Identifier */
+ u_short ch_pid; /* Protocol Identifier */
+};
+
+/*
+ * SPANS ARP Packet Format
+ */
+struct spansarp_hdr {
+ u_short ah_hrd; /* Hardware type (see below) */
+ u_short ah_pro; /* Protocol type */
+ u_char ah_hln; /* Length of hardware address */
+ u_char ah_pln; /* Length of protocol address */
+ u_short ah_op; /* Operation code (see below) */
+ spans_addr ah_sha; /* Source hardware address */
+ u_char ah_spa[4]; /* Source protocol address */
+ spans_addr ah_tha; /* Target hardware address */
+ u_char ah_tpa[4]; /* Target protocol address */
+};
+
+/*
+ * Hardware types
+ */
+#define ARP_SPANS 0x4040
+
+/*
+ * Operation types
+ */
+#define ARP_REQUEST 1 /* SPANSARP request */
+#define ARP_REPLY 2 /* SPANSARP response */
+
+#define ARP_PACKET_LEN \
+ (sizeof(struct spanscls_hdr) + sizeof(struct spansarp_hdr))
+
+#ifdef ATM_KERNEL
+/*
+ * Macros for manipulating SPANS ARP tables and entries
+ */
+#define SPANSARP_HASH(ip) ((u_long)(ip) % SPANSARP_HASHSIZ)
+
+#define SPANSARP_ADD(sa) \
+{ \
+ struct spansarp **h; \
+ h = &spansarp_arptab[SPANSARP_HASH((sa)->sa_dstip.s_addr)]; \
+ LINK2TAIL((sa), struct spansarp, *h, sa_next); \
+}
+
+#define SPANSARP_DELETE(sa) \
+{ \
+ struct spansarp **h; \
+ h = &spansarp_arptab[SPANSARP_HASH((sa)->sa_dstip.s_addr)]; \
+ UNLINK((sa), struct spansarp, *h, sa_next); \
+}
+
+#define SPANSARP_LOOKUP(ip, sa) \
+{ \
+ for ((sa) = spansarp_arptab[SPANSARP_HASH(ip)]; \
+ (sa); (sa) = (sa)->sa_next) { \
+ if ((sa)->sa_dstip.s_addr == (ip)) \
+ break; \
+ } \
+}
+
+
+/*
+ * External variables
+ */
+extern struct spanscls *spanscls_head;
+extern struct spanscls_hdr spanscls_hdr;
+
+#endif /* ATM_KERNEL */
+
+#endif /* _SPANS_SPANSCLS_H */
diff --git a/sys/netatm/spans/spans_if.c b/sys/netatm/spans/spans_if.c
new file mode 100644
index 0000000..4facf73
--- /dev/null
+++ b/sys/netatm/spans/spans_if.c
@@ -0,0 +1,1336 @@
+/*
+ *
+ * ===================================
+ * 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: spans_if.c,v 1.12 1998/08/26 23:29:09 mks Exp $
+ *
+ */
+
+/*
+ * SPANS Signalling Manager
+ * ---------------------------
+ *
+ * External interfaces to SPANS manager. Includes support for
+ * running as a loadable kernel module.
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: spans_if.c,v 1.12 1998/08/26 23:29:09 mks Exp $";
+#endif
+
+#ifndef ATM_SPANS_MODULE
+#include "opt_atm.h"
+#endif
+
+#include <netatm/kern_include.h>
+
+#include "spans_xdr.h"
+#include <netatm/spans/spans_var.h>
+
+/*
+ * Global variables
+ */
+struct sp_info spans_vcpool = {
+ "spans vcc pool", /* si_name */
+ sizeof(struct spans_vccb), /* si_blksiz */
+ 10, /* si_blkcnt */
+ 50 /* si_maxallow */
+};
+
+struct sp_info spans_msgpool = {
+ "spans message pool", /* si_name */
+ sizeof(spans_msg), /* si_blksiz */
+ 10, /* si_blkcnt */
+ 50 /* si_maxallow */
+};
+
+/*
+ * Local functions
+ */
+static int spans_start __P((void));
+static int spans_stop __P((void));
+static int spans_attach __P((struct sigmgr *, struct atm_pif *));
+static int spans_detach __P((struct atm_pif *));
+static int spans_setup __P((Atm_connvc *, int *));
+static int spans_release __P((struct vccb *, int *));
+static int spans_accept __P((struct vccb *, int *));
+static int spans_reject __P((struct vccb *, int *));
+static int spans_ioctl __P((int, caddr_t, caddr_t));
+
+/*
+ * Local variables
+ */
+static struct sigmgr *spans_mgr = NULL;
+
+
+/*
+ * Initialize SPANS processing
+ *
+ * This will be called during module loading. We'll just register
+ * the SPANS protocol descriptor and wait for a SPANS ATM interface
+ * to come online.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 startup was successful
+ * errno startup failed - reason indicated
+ *
+ */
+static int
+spans_start()
+{
+ int err = 0;
+
+ /*
+ * Verify software version
+ */
+ if (atm_version != ATM_VERSION) {
+ log(LOG_ERR, "version mismatch: spans=%d.%d kernel=%d.%d\n",
+ ATM_VERS_MAJ(ATM_VERSION),
+ ATM_VERS_MIN(ATM_VERSION),
+ ATM_VERS_MAJ(atm_version),
+ ATM_VERS_MIN(atm_version));
+ return (EINVAL);
+ }
+
+ /*
+ * Allocate protocol definition structure
+ */
+ spans_mgr = (struct sigmgr *)KM_ALLOC(sizeof(struct sigmgr),
+ M_DEVBUF, M_NOWAIT);
+ if (spans_mgr == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+ KM_ZERO(spans_mgr, sizeof(struct sigmgr));
+
+ /*
+ * Initialize protocol invariant values
+ */
+ spans_mgr->sm_proto = ATM_SIG_SPANS;
+ spans_mgr->sm_attach = spans_attach;
+ spans_mgr->sm_detach = spans_detach;
+ spans_mgr->sm_setup = spans_setup;
+ spans_mgr->sm_release = spans_release;
+ spans_mgr->sm_accept = spans_accept;
+ spans_mgr->sm_reject = spans_reject;
+ spans_mgr->sm_free = spans_free;
+ spans_mgr->sm_ioctl = spans_ioctl;
+
+ /*
+ * Register ourselves with system
+ */
+ err = atm_sigmgr_register(spans_mgr);
+ if (err)
+ goto done;
+
+ /*
+ * Start up Connectionless Service
+ */
+ err = spanscls_start();
+ if (err)
+ goto done;
+
+done:
+ return (err);
+}
+
+
+/*
+ * Halt SPANS processing
+ *
+ * This should be called just prior to unloading the module from
+ * memory. All SPANS interfaces must be deregistered before the
+ * protocol can be shutdown.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 startup was successful
+ * errno startup failed - reason indicated
+ *
+ */
+static int
+spans_stop()
+{
+ int err = 0;
+ int s = splnet();
+
+ /*
+ * Is protocol even set up?
+ */
+ if (spans_mgr) {
+
+ /*
+ * Any protocol instances still registered?
+ */
+ if (spans_mgr->sm_prinst) {
+
+ /* Yes, can't stop now */
+ err = EBUSY;
+ goto done;
+ }
+
+ /*
+ * Stop Connectionless Service
+ */
+ spanscls_stop();
+
+ /*
+ * De-register from system
+ */
+ err = atm_sigmgr_deregister(spans_mgr);
+
+ /*
+ * Free up protocol block
+ */
+ KM_FREE(spans_mgr, sizeof(struct sigmgr), M_DEVBUF);
+ spans_mgr = NULL;
+
+ /*
+ * Free up our storage pools
+ */
+ atm_release_pool(&spans_vcpool);
+ atm_release_pool(&spans_msgpool);
+ } else
+ err = ENXIO;
+
+done:
+ (void) splx(s);
+ return (err);
+}
+
+
+/*
+ * Attach a SPANS-controlled interface
+ *
+ * Each ATM physical interface must be attached with the signalling
+ * manager for the interface's signalling protocol (via the
+ * atm_sigmgr_attach function). This function will handle the
+ * attachment for SPANS-controlled interfaces. A new SPANS protocol
+ * instance will be created and then we'll just sit around waiting for
+ * status or connection requests.
+ *
+ * Function must be called at splnet.
+ *
+ * Arguments:
+ * smp pointer to SPANS signalling manager control block
+ * pip pointer to ATM physical interface control block
+ *
+ * Returns:
+ * 0 attach successful
+ * errno attach failed - reason indicated
+ *
+ */
+static int
+spans_attach(smp, pip)
+ struct sigmgr *smp;
+ struct atm_pif *pip;
+{
+ int err = 0, n = 0, s;
+ struct spans *spp = NULL;
+ struct atm_nif *np;
+
+ ATM_DEBUG2("spans_attach: smp=%x, pip=%x\n", smp, pip);
+
+ /*
+ * Count network interfaces attached to the physical interface.
+ * If there are more or less than one, we have big problems.
+ */
+ np = pip->pif_nif;
+ while (np) {
+ n++;
+ np = np->nif_pnext;
+ }
+ if (n != 1) {
+ err = ETOOMANYREFS;
+ goto done;
+ }
+
+ /*
+ * Allocate SPANS protocol instance control block
+ */
+ spp = (struct spans *)KM_ALLOC(sizeof(struct spans),
+ M_DEVBUF, M_NOWAIT);
+ if (spp == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+ KM_ZERO(spp, sizeof(struct spans));
+
+ /*
+ * Set variables in SPANS protocol instance control block
+ */
+ spp->sp_state = SPANS_INIT;
+ spp->sp_h_epoch = time_second;
+ spp->sp_s_epoch = 0;
+ spp->sp_addr.address_format = T_ATM_ABSENT;
+ spp->sp_addr.address_length = 0;
+ spp->sp_subaddr.address_format = T_ATM_ABSENT;
+ spp->sp_subaddr.address_length = 0;
+ spp->sp_probe_ct = 0;
+ spp->sp_alloc_vci = SPANS_MIN_VCI;
+ spp->sp_alloc_vpi = SPANS_VPI;
+ spp->sp_min_vci = SPANS_MIN_VCI;
+ spp->sp_max_vci = pip->pif_maxvci;
+
+ /*
+ * Link instance into manager's chain
+ */
+ LINK2TAIL((struct siginst *)spp, struct siginst, smp->sm_prinst,
+ si_next);
+
+ /*
+ * Link in interface
+ */
+ spp->sp_pif = pip;
+ pip->pif_sigmgr = smp;
+ pip->pif_siginst = (struct siginst *) spp;
+
+ /*
+ * Kick-start the SPANS protocol
+ */
+ SPANS_TIMER(spp, 0);
+
+ /*
+ * Notify Connectionless Service
+ */
+ err = spanscls_attach(spp);
+
+ /*
+ * Log the fact that we've attached
+ */
+ if (!err)
+ log(LOG_INFO, "spans: attached to interface %s%d\n",
+ pip->pif_name, pip->pif_unit);
+
+done:
+ /*
+ * Reset our work if attach fails
+ */
+ if (err) {
+ if (spp) {
+ SPANS_CANCEL(spp);
+ UNLINK((struct siginst *)spp, struct siginst,
+ smp->sm_prinst, si_next);
+ KM_FREE(spp, sizeof(struct spans), M_DEVBUF);
+ }
+ s = splimp();
+ pip->pif_sigmgr = NULL;
+ pip->pif_siginst = NULL;
+ (void) splx(s);
+ }
+
+ return (err);
+}
+
+
+/*
+ * Detach a SPANS-controlled interface
+ *
+ * Each ATM physical interface may be detached from its signalling
+ * manager (via the atm_sigmgr_detach function). This function will
+ * handle the detachment for all SPANS-controlled interfaces. All
+ * circuits will be immediately terminated.
+ *
+ * Function must be called at splnet.
+ *
+ * Arguments:
+ * pip pointer to ATM physical interface control block
+ *
+ * Returns:
+ * 0 detach successful
+ * errno detach failed - reason indicated
+ *
+ */
+static int
+spans_detach(pip)
+ struct atm_pif *pip;
+{
+ struct spans *spp;
+ struct vccb *vcp, *vnext;
+ Atm_connection *cop;
+ int err;
+
+ ATM_DEBUG1("spans_detach: pip=0x%x\n", pip);
+
+ /*
+ * Get SPANS protocol instance
+ */
+ spp = (struct spans *)pip->pif_siginst;
+
+ /*
+ * Return an error if we're already detaching
+ */
+ if (spp->sp_state == SPANS_DETACH) {
+ return(EALREADY);
+ }
+
+ /*
+ * Cancel any outstanding timer
+ */
+ SPANS_CANCEL(spp);
+
+ /*
+ * Notify Connectionless Service
+ */
+ spanscls_detach(spp);
+
+ /*
+ * Terminate all of our VCCs
+ */
+ for (vcp = Q_HEAD(spp->sp_vccq, struct vccb); vcp; vcp = vnext) {
+
+ vnext = Q_NEXT(vcp, struct vccb, vc_sigelem);
+
+ /*
+ * Don't close the signalling VCC yet
+ */
+ if (vcp->vc_connvc && vcp->vc_connvc->cvc_conn ==
+ spp->sp_conn)
+ continue;
+
+ /*
+ * Close VCC and notify owner
+ */
+ err = spans_clear_vcc(spp, (struct spans_vccb *)vcp);
+ if (err) {
+ log(LOG_ERR, "spans: error %d clearing VCCB 0x%x\n",
+ err, vcp);
+ }
+ }
+
+ /*
+ * Now close the SPANS signalling VCC
+ */
+ if (cop = spp->sp_conn) {
+ err = atm_cm_release(cop, &spans_cause);
+ if (err)
+ ATM_DEBUG2(
+ "spans_detach: close failed for SPANS signalling channel; cop=0x%x, err=%d\n",
+ cop, err);
+ }
+
+
+ /*
+ * Get rid of protocol instance if there are no VCCs queued
+ */
+ if (Q_HEAD(spp->sp_vccq, struct vccb) == NULL) {
+ struct sigmgr *smp = pip->pif_sigmgr;
+
+ pip->pif_sigmgr = NULL;
+ pip->pif_siginst = NULL;
+ UNLINK((struct siginst *)spp, struct siginst,
+ smp->sm_prinst, si_next);
+ KM_FREE(spp, sizeof(struct spans), M_DEVBUF);
+ } else {
+ /*
+ * Otherwise, wait for protocol instance to be freed
+ * during spans_free processing for the last queued VCC.
+ */
+ spp->sp_state = SPANS_DETACH;
+ }
+
+ /*
+ * Log the fact that we've detached
+ */
+ log(LOG_INFO, "spans: detached from interface %s%d\n",
+ pip->pif_name, pip->pif_unit);
+
+ return (0);
+}
+
+
+/*
+ * Open a SPANS ATM Connection
+ *
+ * All service user requests to open a VC connection (via
+ * atm_open_connection) over an ATM interface attached to the SPANS
+ * signalling manager are handled here.
+ *
+ * Function will be called at splnet.
+ *
+ * Arguments:
+ * cvp pointer to user's requested connection parameters
+ * errp pointer to an int for extended error information
+ *
+ * Returns:
+ * CALL_PROCEEDING connection establishment is in progress
+ * CALL_FAILED connection establishment failed
+ * CALL_CONNECTED connection has been successfully established
+ *
+ */
+static int
+spans_setup(cvp, errp)
+ Atm_connvc *cvp;
+ int *errp;
+{
+ struct atm_pif *pip = cvp->cvc_attr.nif->nif_pif;
+ struct spans *spp = (struct spans *)pip->pif_siginst;
+ int rc = 0;
+
+ ATM_DEBUG1("spans_setup: cvp=0x%x\n", cvp);
+
+ /*
+ * Intialize the returned error code
+ */
+ *errp = 0;
+
+ /*
+ * Open the connection
+ */
+ switch (cvp->cvc_attr.called.addr.address_format) {
+ case T_ATM_PVC_ADDR:
+ /*
+ * Create a PVC
+ */
+ *errp = spans_open_vcc(spp, cvp);
+ rc = (*errp ? CALL_FAILED : CALL_CONNECTED);
+ break;
+
+ case T_ATM_SPANS_ADDR:
+
+ /*
+ * Create an SVC
+ */
+ *errp = spans_open_vcc(spp, cvp);
+ rc = (*errp ? CALL_FAILED : CALL_PROCEEDING);
+ break;
+
+ default:
+ *errp = EPROTONOSUPPORT;
+ rc = CALL_FAILED;
+ }
+
+ return (rc);
+}
+
+
+/*
+ * Close a SPANS ATM Connection
+ *
+ * All service user requests to terminate a previously open VC
+ * connection (via the atm_close_connection function), which is running
+ * over an interface attached to the SPANS signalling manager, are
+ * handled here.
+ *
+ * Function will be called at splnet.
+ *
+ * Arguments:
+ * vcp pointer to connection's VC control block
+ * errp pointer to an int for extended error information
+ *
+ * Returns:
+ * CALL_PROCEEDING connection termination is in progress
+ * CALL_FAILED connection termination failed
+ * CALL_CLEARED connection has been successfully terminated
+ *
+ */
+static int
+spans_release(vcp, errp)
+ struct vccb *vcp;
+ int *errp;
+{
+ int rc = 0;
+ struct atm_pif *pip = vcp->vc_pif;
+ struct spans *spp = (struct spans *)pip->pif_siginst;
+
+ ATM_DEBUG1("spans_release: vcp=0x%x\n", vcp);
+
+ /*
+ * Initialize returned error code
+ */
+ *errp = 0;
+
+ /*
+ * Make sure VCC is open
+ */
+ if ((vcp->vc_sstate == SPANS_VC_NULL) ||
+ (vcp->vc_sstate == SPANS_VC_CLOSE) ||
+ (vcp->vc_sstate == SPANS_VC_FREE) ||
+ (vcp->vc_ustate == VCCU_NULL) ||
+ (vcp->vc_ustate == VCCU_CLOSED)) {
+ *errp = EALREADY;
+ return(CALL_FAILED);
+ }
+
+ /*
+ * Validate the connection type (PVC or SVC)
+ */
+ if (!(vcp->vc_type & (VCC_PVC | VCC_SVC))) {
+ *errp = EPROTONOSUPPORT;
+ return(CALL_FAILED);
+ }
+
+ /*
+ * Close the VCCB
+ */
+ *errp = spans_close_vcc(spp, (struct spans_vccb *)vcp, FALSE);
+
+ /*
+ * Set the return code
+ */
+ if (vcp->vc_type & VCC_PVC) {
+ rc = (*errp ? CALL_FAILED : CALL_CLEARED);
+ } else {
+ rc = (*errp ? CALL_FAILED : CALL_PROCEEDING);
+ }
+
+ return (rc);
+}
+
+
+/*
+ * Accept a SPANS Open from a remote host
+ *
+ * A user calls this routine (via the atm_accept_call function)
+ * after it is notified that an open request was received for it.
+ *
+ * Function will be called at splnet.
+ *
+ * Arguments:
+ * vcp pointer to user's VCCB
+ * errp pointer to an int for extended error information
+ *
+ * Returns:
+ * CALL_PROCEEDING connection establishment is in progress
+ * CALL_FAILED connection establishment failed
+ * CALL_CONNECTED connection has been successfully established
+ *
+ */
+static int
+spans_accept(vcp, errp)
+ struct vccb *vcp;
+ int *errp;
+{
+ struct atm_pif *pip = vcp->vc_pif;
+ struct spans *spp = (struct spans *)pip->pif_siginst;
+ struct spans_vccb *svp = (struct spans_vccb *)vcp;
+
+ ATM_DEBUG1("spans_accept: vcp=0x%x\n", vcp);
+
+ /*
+ * Initialize the returned error code
+ */
+ *errp = 0;
+
+ /*
+ * Return an error if we're detaching
+ */
+ if (spp->sp_state == SPANS_DETACH) {
+ *errp = ENETDOWN;
+ ATM_DEBUG0("spans_accept: detaching\n");
+ return(CALL_FAILED);
+ }
+
+ /*
+ * Respond to the open request
+ */
+ *errp = spans_send_open_rsp(spp, svp, SPANS_OK);
+ if (*errp) {
+ ATM_DEBUG0("spans_accept: spans_send_open_rsp failed\n");
+ goto failed;
+ }
+
+ /*
+ * Update the VCC states
+ */
+ svp->sv_sstate = SPANS_VC_OPEN;
+ svp->sv_ustate = VCCU_OPEN;
+
+ return(CALL_CONNECTED);
+
+failed:
+ /*
+ * On error, free the VCCB and return CALL_FAILED
+ */
+ svp->sv_sstate = SPANS_VC_FREE;
+ svp->sv_ustate = VCCU_CLOSED;
+ DEQUEUE(svp, struct spans_vccb, sv_sigelem, spp->sp_vccq);
+ spans_free((struct vccb *)svp);
+
+ return(CALL_FAILED);
+}
+
+
+/*
+ * Reject a SPANS Open from a remote host
+ *
+ * A user calls this routine (via the atm_reject_call function)
+ * after it is notified that an open request was received for it.
+ *
+ * Function will be called at splnet.
+ *
+ * Arguments:
+ * vcp pointer to user's VCCB
+ * errp pointer to an int for extended error information
+ *
+ * Returns:
+ * CALL_CLEARED call request rejected
+ * CALL_FAILED call rejection failed
+ *
+ */
+static int
+spans_reject(vcp, errp)
+ struct vccb *vcp;
+ int *errp;
+{
+ struct atm_pif *pip = vcp->vc_pif;
+ struct spans *spp = (struct spans *)pip->pif_siginst;
+ struct spans_vccb *svp = (struct spans_vccb *)vcp;
+
+ ATM_DEBUG1("spans_reject: vcp=0x%x\n", vcp);
+
+ /*
+ * Initialize the returned error code
+ */
+ *errp = 0;
+
+ /*
+ * Return an error if we're detaching
+ */
+ if (spp->sp_state == SPANS_DETACH) {
+ *errp = ENETDOWN;
+ ATM_DEBUG0("spans_reject: detaching\n");
+ return(CALL_FAILED);
+ }
+
+ ATM_DEBUG1("spans_reject: cause code is %d\n",
+ vcp->vc_connvc->cvc_attr.cause.v.cause_value);
+
+ /*
+ * Clean up the VCCB--the connection manager will free it
+ * spans_close_vcc will send a SPANS open response
+ */
+ if (*errp = spans_close_vcc(spp, svp, TRUE)) {
+ ATM_DEBUG0("spans_reject: spans_close_vcc failed\n");
+ return(CALL_FAILED);
+ }
+
+ return(CALL_CLEARED);
+}
+
+
+/*
+ * Abort a SPANS ATM Connection
+ *
+ * All (non-user) requests to abort a previously open VC connection (via
+ * the atm_abort_connection function), which is running over an
+ * interface attached to the SPANS signalling manager, are handled here.
+ * The VCC owner will be notified of the request, in order to initiate
+ * termination of the connection.
+ *
+ * Function will be called at splnet.
+ *
+ * Arguments:
+ * vcp pointer to connection's VC control block
+ *
+ * Returns:
+ * 0 connection release was succesful
+ * errno connection release failed - reason indicated
+ *
+ */
+int
+spans_abort(vcp)
+ struct vccb *vcp;
+{
+
+ /*
+ * Make sure VCC is available
+ */
+ if ((vcp->vc_sstate == SPANS_VC_NULL) ||
+ (vcp->vc_sstate == SPANS_VC_CLOSE) ||
+ (vcp->vc_sstate == SPANS_VC_FREE) ||
+ (vcp->vc_ustate == VCCU_NULL) ||
+ (vcp->vc_ustate == VCCU_CLOSED)) {
+ return(EALREADY);
+ }
+
+ /*
+ * Only abort once
+ */
+ if (vcp->vc_sstate == SPANS_VC_ABORT) {
+ return (EALREADY);
+ }
+
+ /*
+ * Cancel any timer that might be running
+ */
+ SPANS_VC_CANCEL(vcp);
+
+ /*
+ * Set immediate timer to schedule connection termination
+ */
+ vcp->vc_sstate = SPANS_VC_ABORT;
+ SPANS_VC_TIMER(vcp, 0);
+
+ return (0);
+}
+
+
+/*
+ * Free SPANS ATM connection resources
+ *
+ * All service user requests to free the resources of a closed
+ * VCC connection (via the atm_free_connection function), which
+ * is running over an interface attached to the SigPVC signalling
+ * manager, are handled here.
+ *
+ * Function will be called at splnet.
+ *
+ * Arguments:
+ * vcp pointer to connection's VC control block
+ *
+ * Returns:
+ * 0 connection free was successful
+ * errno connection free failed - reason indicated
+ *
+ */
+int
+spans_free(vcp)
+ struct vccb *vcp;
+{
+ struct atm_pif *pip = vcp->vc_pif;
+ struct spans *spp = (struct spans *)pip->pif_siginst;
+
+ ATM_DEBUG1("spans_free: vcp = 0x%x\n", vcp);
+
+ /*
+ * Make sure VCC has been closed
+ */
+ if ((vcp->vc_ustate != VCCU_CLOSED) ||
+ (vcp->vc_sstate != SPANS_VC_FREE)) {
+ ATM_DEBUG2("spans_free: bad state, sstate=%d, ustate=%d\n",
+ vcp->vc_sstate, vcp->vc_ustate);
+ return(EEXIST);
+ }
+
+ /*
+ * Remove VCCB from protocol queue
+ */
+ DEQUEUE(vcp, struct vccb, vc_sigelem, spp->sp_vccq);
+
+ /*
+ * Free VCCB storage
+ */
+ vcp->vc_ustate = VCCU_NULL;
+ vcp->vc_sstate = SPANS_VC_NULL;
+ atm_free((caddr_t)vcp);
+
+ /*
+ * If we're detaching and this was the last VCC queued,
+ * get rid of the protocol instance
+ */
+ if ((spp->sp_state == SPANS_DETACH) &&
+ (Q_HEAD(spp->sp_vccq, struct vccb) == NULL)) {
+ struct sigmgr *smp = pip->pif_sigmgr;
+
+ pip->pif_sigmgr = NULL;
+ pip->pif_siginst = NULL;
+ UNLINK((struct siginst *)spp, struct siginst, smp->sm_prinst,
+ si_next);
+ KM_FREE(spp, sizeof(struct spans), M_DEVBUF);
+ }
+
+ return (0);
+}
+
+
+/*
+ * SPANS IOCTL support
+ *
+ * Function will be called at splnet.
+ *
+ * Arguments:
+ * code PF_ATM sub-operation code
+ * data pointer to code specific parameter data area
+ * arg1 pointer to code specific argument
+ *
+ * Returns:
+ * 0 request procesed
+ * errno error processing request - reason indicated
+ *
+ */
+static int
+spans_ioctl(code, data, arg1)
+ int code;
+ caddr_t data;
+ caddr_t arg1;
+{
+ struct atmdelreq *adp;
+ struct atminfreq *aip;
+ struct spans *spp;
+ struct spans_vccb *svp;
+ struct air_vcc_rsp rsp;
+ Atm_connection *cop;
+ int buf_len, err = 0, i, vpi, vci;
+ caddr_t buf_addr;
+
+
+ switch (code) {
+
+ case AIOCS_DEL_PVC:
+ case AIOCS_DEL_SVC:
+ /*
+ * Delete a VCC
+ */
+ adp = (struct atmdelreq *)data;
+ spp = (struct spans *)arg1;
+
+ /*
+ * Don't let a user close the SPANS signalling VC or
+ * the SPANS CLS VC
+ */
+ vpi = adp->adr_pvc_vpi;
+ vci = adp->adr_pvc_vci;
+ if ((vpi == SPANS_SIG_VPI && vci == SPANS_SIG_VCI) ||
+ (vpi == SPANS_CLS_VPI &&
+ vci == SPANS_CLS_VCI))
+ return(EINVAL);
+
+ /*
+ * Find requested VCC
+ */
+ for (svp = Q_HEAD(spp->sp_vccq, struct spans_vccb); svp;
+ svp = Q_NEXT(svp, struct spans_vccb, sv_sigelem)) {
+ if ((svp->sv_vpi == vpi) && (svp->sv_vci == vci))
+ break;
+ }
+ if (svp == NULL)
+ return (ENOENT);
+
+ /*
+ * Check VCC type
+ */
+ switch (code) {
+ case AIOCS_DEL_PVC:
+ if (!(svp->sv_type & VCC_PVC)) {
+ return(EINVAL);
+ }
+ break;
+ case AIOCS_DEL_SVC:
+ if (!(svp->sv_type & VCC_SVC)) {
+ return(EINVAL);
+ }
+ break;
+ }
+
+ /*
+ * Schedule VCC termination
+ */
+ err = spans_abort((struct vccb *)svp);
+ break;
+
+ case AIOCS_INF_VCC:
+ /*
+ * Return VCC information
+ */
+ aip = (struct atminfreq *)data;
+ spp = (struct spans *)arg1;
+
+ buf_addr = aip->air_buf_addr;
+ buf_len = aip->air_buf_len;
+
+ /*
+ * Loop through the VCC queue
+ */
+ for (svp = Q_HEAD(spp->sp_vccq, struct spans_vccb); svp;
+ svp = Q_NEXT(svp, struct spans_vccb, sv_sigelem)) {
+ /*
+ * Make sure there's room in the user's buffer
+ */
+ if (buf_len < sizeof(rsp)) {
+ err = ENOSPC;
+ break;
+ }
+
+ /*
+ * Fill out the response struct for the VCC
+ */
+ (void) sprintf(rsp.avp_intf, "%s%d",
+ spp->sp_pif->pif_name,
+ spp->sp_pif->pif_unit);
+ rsp.avp_vpi = svp->sv_vpi;
+ rsp.avp_vci = svp->sv_vci;
+ rsp.avp_type = svp->sv_type;
+ rsp.avp_aal = svp->sv_connvc->cvc_attr.aal.type;
+ rsp.avp_sig_proto = svp->sv_proto;
+ cop = svp->sv_connvc->cvc_conn;
+ if (cop)
+ rsp.avp_encaps = cop->co_mpx;
+ else
+ rsp.avp_encaps = 0;
+ rsp.avp_state = svp->sv_sstate;
+ KM_ZERO(rsp.avp_owners, sizeof(rsp.avp_owners));
+ for (i = 0; cop && i < sizeof(rsp.avp_owners);
+ cop = cop->co_next,
+ i += T_ATM_APP_NAME_LEN+1) {
+ strncpy(&rsp.avp_owners[i],
+ cop->co_endpt->ep_getname(cop->co_toku),
+ T_ATM_APP_NAME_LEN);
+ }
+ rsp.avp_daddr.address_format = T_ATM_SPANS_ADDR;
+ rsp.avp_daddr.address_length =
+ sizeof(Atm_addr_spans);
+ if (svp->sv_type & VCC_OUT) {
+ spans_addr_copy(&svp->sv_conn.con_dst,
+ rsp.avp_daddr.address);
+ } else {
+ spans_addr_copy(&svp->sv_conn.con_src,
+ rsp.avp_daddr.address);
+ }
+ rsp.avp_dsubaddr.address_format = T_ATM_ABSENT;
+ rsp.avp_dsubaddr.address_length = 0;
+ rsp.avp_ipdus = svp->sv_ipdus;
+ rsp.avp_opdus = svp->sv_opdus;
+ rsp.avp_ibytes = svp->sv_ibytes;
+ rsp.avp_obytes = svp->sv_obytes;
+ rsp.avp_ierrors = svp->sv_ierrors;
+ rsp.avp_oerrors = svp->sv_oerrors;
+ rsp.avp_tstamp = svp->sv_tstamp;
+
+ /*
+ * Copy the response into the user's buffer
+ */
+ if (err = copyout((caddr_t)&rsp, buf_addr,
+ sizeof(rsp)))
+ break;
+ buf_addr += sizeof(rsp);
+ buf_len -= sizeof(rsp);
+ }
+
+ /*
+ * Update the buffer pointer and length
+ */
+ aip->air_buf_addr = buf_addr;
+ aip->air_buf_len = buf_len;
+ break;
+
+ case AIOCS_ADD_ARP:
+ case AIOCS_DEL_ARP:
+ case AIOCS_INF_ARP:
+ case AIOCS_INF_ASV:
+ /*
+ * ARP specific ioctl's
+ */
+ err = spansarp_ioctl(code, data, arg1);
+ break;
+
+ default:
+ err = EOPNOTSUPP;
+ }
+
+ return (err);
+}
+
+
+#ifdef ATM_SPANS_MODULE
+/*
+ *******************************************************************
+ *
+ * Loadable Module Support
+ *
+ *******************************************************************
+ */
+static int spans_doload __P((void));
+static int spans_dounload __P((void));
+
+/*
+ * Generic module load processing
+ *
+ * This function is called by an OS-specific function when this
+ * module is being loaded.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 load was successful
+ * errno load failed - reason indicated
+ *
+ */
+static int
+spans_doload()
+{
+ int err = 0;
+
+ /*
+ * Start us up
+ */
+ err = spans_start();
+ if (err)
+ /* Problems, clean up */
+ (void)spans_stop();
+
+ return (err);
+}
+
+
+/*
+ * Generic module unload processing
+ *
+ * This function is called by an OS-specific function when this
+ * module is being unloaded.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 unload was successful
+ * errno unload failed - reason indicated
+ *
+ */
+static int
+spans_dounload()
+{
+ int err = 0;
+
+ /*
+ * OK, try to clean up our mess
+ */
+ err = spans_stop();
+
+ return (err);
+}
+
+
+#ifdef sun
+/*
+ * Loadable driver description
+ */
+struct vdldrv spans_drv = {
+ VDMAGIC_PSEUDO, /* Pseudo Driver */
+ "spans_mod", /* name */
+ NULL, /* dev_ops */
+ NULL, /* bdevsw */
+ NULL, /* cdevsw */
+ 0, /* blockmajor */
+ 0 /* charmajor */
+};
+
+
+/*
+ * Loadable module support entry point
+ *
+ * This is the routine called by the vd driver for all loadable module
+ * functions for this pseudo driver. This routine name must be specified
+ * on the modload(1) command. This routine will be called whenever the
+ * modload(1), modunload(1) or modstat(1) commands are issued for this
+ * module.
+ *
+ * Arguments:
+ * cmd vd command code
+ * vdp pointer to vd driver's structure
+ * vdi pointer to command-specific vdioctl_* structure
+ * vds pointer to status structure (VDSTAT only)
+ *
+ * Returns:
+ * 0 command was successful
+ * errno command failed - reason indicated
+ *
+ */
+int
+spans_mod(cmd, vdp, vdi, vds)
+ int cmd;
+ struct vddrv *vdp;
+ caddr_t vdi;
+ struct vdstat *vds;
+{
+ int err = 0;
+
+ switch (cmd) {
+
+ case VDLOAD:
+ /*
+ * Module Load
+ *
+ * We dont support any user configuration
+ */
+ err = spans_doload();
+ if (err == 0)
+ /* Let vd driver know about us */
+ vdp->vdd_vdtab = (struct vdlinkage *)&spans_drv;
+ break;
+
+ case VDUNLOAD:
+ /*
+ * Module Unload
+ */
+ err = spans_dounload();
+ break;
+
+ case VDSTAT:
+ /*
+ * Module Status
+ */
+
+ /* Not much to say at the moment */
+
+ break;
+
+ default:
+ log(LOG_ERR, "spans_mod: Unknown vd command 0x%x\n", cmd);
+ err = EINVAL;
+ }
+
+ return (err);
+}
+#endif /* sun */
+
+#ifdef __FreeBSD__
+
+#include <sys/exec.h>
+#include <sys/sysent.h>
+#include <sys/lkm.h>
+
+/*
+ * Loadable miscellaneous module description
+ */
+MOD_MISC(spans);
+
+
+/*
+ * Loadable module support "load" entry point
+ *
+ * This is the routine called by the lkm driver whenever the
+ * modload(1) command is issued for this module.
+ *
+ * Arguments:
+ * lkmtp pointer to lkm drivers's structure
+ * cmd lkm command code
+ *
+ * Returns:
+ * 0 command was successful
+ * errno command failed - reason indicated
+ *
+ */
+static int
+spans_load(lkmtp, cmd)
+ struct lkm_table *lkmtp;
+ int cmd;
+{
+ return(spans_doload());
+}
+
+
+/*
+ * Loadable module support "unload" entry point
+ *
+ * This is the routine called by the lkm driver whenever the
+ * modunload(1) command is issued for this module.
+ *
+ * Arguments:
+ * lkmtp pointer to lkm drivers's structure
+ * cmd lkm command code
+ *
+ * Returns:
+ * 0 command was successful
+ * errno command failed - reason indicated
+ *
+ */
+static int
+spans_unload(lkmtp, cmd)
+ struct lkm_table *lkmtp;
+ int cmd;
+{
+ return(spans_dounload());
+}
+
+
+/*
+ * Loadable module support entry point
+ *
+ * This is the routine called by the lkm driver for all loadable module
+ * functions for this driver. This routine name must be specified
+ * on the modload(1) command. This routine will be called whenever the
+ * modload(1), modunload(1) or modstat(1) commands are issued for this
+ * module.
+ *
+ * Arguments:
+ * lkmtp pointer to lkm drivers's structure
+ * cmd lkm command code
+ * ver lkm version
+ *
+ * Returns:
+ * 0 command was successful
+ * errno command failed - reason indicated
+ *
+ */
+int
+spans_mod(lkmtp, cmd, ver)
+ struct lkm_table *lkmtp;
+ int cmd;
+ int ver;
+{
+ MOD_DISPATCH(spans, lkmtp, cmd, ver,
+ spans_load, spans_unload, lkm_nullcmd);
+}
+#endif /* __FreeBSD__ */
+
+#else /* !ATM_SPANS_MODULE */
+
+/*
+ *******************************************************************
+ *
+ * Kernel Compiled Module Support
+ *
+ *******************************************************************
+ */
+static void spans_doload __P((void *));
+
+SYSINIT(atmspans, SI_SUB_PROTO_END, SI_ORDER_ANY, spans_doload, NULL)
+
+/*
+ * Kernel initialization
+ *
+ * Arguments:
+ * arg Not used
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+spans_doload(void *arg)
+{
+ int err = 0;
+
+ /*
+ * Start us up
+ */
+ err = spans_start();
+ if (err) {
+ /* Problems, clean up */
+ (void)spans_stop();
+
+ log(LOG_ERR, "ATM SPANS unable to initialize (%d)!!\n", err);
+ }
+ return;
+}
+#endif /* ATM_SPANS_MODULE */
+
diff --git a/sys/netatm/spans/spans_kxdr.c b/sys/netatm/spans/spans_kxdr.c
new file mode 100644
index 0000000..b6534de
--- /dev/null
+++ b/sys/netatm/spans/spans_kxdr.c
@@ -0,0 +1,684 @@
+/*
+ *
+ * ===================================
+ * 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: spans_kxdr.c,v 1.2 1997/05/06 22:17:00 mks Exp $
+ *
+ */
+
+/*
+ * SPANS Signalling Manager
+ * ---------------------------
+ *
+ * Kernel XDR (External Data Representation) routines
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: spans_kxdr.c,v 1.2 1997/05/06 22:17:00 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+/*
+ * This file contains code that has been copied and/or modified from
+ * the following FreeBSD files:
+ *
+ * /usr/src/lib/libc/xdr/xdr.c
+ * /usr/src/lib/libc/xdr/xdr_mem.c
+ *
+ * which are covered by the copyright notice below.
+ */
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#if !defined(sun)
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)xdr.c 1.35 87/08/12";*/
+/*static char *sccsid = "from: @(#)xdr.c 2.1 88/07/29 4.0 RPCSRC";*/
+/*static char *rcsid = "Id: xdr.c,v 1.2.4.2 1996/06/05 02:52:02 jkh Exp";*/
+#endif
+
+/*
+ * xdr.c, Generic XDR routines implementation.
+ *
+ * Copyright (C) 1986, Sun Microsystems, Inc.
+ *
+ * These are the "generic" xdr routines used to serialize and de-serialize
+ * most common data items. See xdr.h for more info on the interface to
+ * xdr.
+ */
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+
+/*
+ * constants specific to the xdr "protocol"
+ */
+#define XDR_FALSE ((long) 0)
+#define XDR_TRUE ((long) 1)
+#define LASTUNSIGNED ((u_int) 0-1)
+
+/*
+ * for unit alignment
+ */
+static char xdr_zero[BYTES_PER_XDR_UNIT] = { 0, 0, 0, 0 };
+
+/*
+ * XDR integers
+ */
+bool_t
+xdr_int(xdrs, ip)
+ XDR *xdrs;
+ int *ip;
+{
+
+#ifdef lint
+ (void) (xdr_short(xdrs, (short *)ip));
+ return (xdr_long(xdrs, (long *)ip));
+#else
+ if (sizeof (int) == sizeof (long)) {
+ return (xdr_long(xdrs, (long *)ip));
+ } else {
+ return (xdr_short(xdrs, (short *)ip));
+ }
+#endif
+}
+
+/*
+ * XDR unsigned integers
+ */
+bool_t
+xdr_u_int(xdrs, up)
+ XDR *xdrs;
+ u_int *up;
+{
+
+#ifdef lint
+ (void) (xdr_short(xdrs, (short *)up));
+ return (xdr_u_long(xdrs, (u_long *)up));
+#else
+ if (sizeof (u_int) == sizeof (u_long)) {
+ return (xdr_u_long(xdrs, (u_long *)up));
+ } else {
+ return (xdr_short(xdrs, (short *)up));
+ }
+#endif
+}
+
+/*
+ * XDR long integers
+ * same as xdr_u_long - open coded to save a proc call!
+ */
+bool_t
+xdr_long(xdrs, lp)
+ register XDR *xdrs;
+ long *lp;
+{
+
+ if (xdrs->x_op == XDR_ENCODE)
+ return (XDR_PUTLONG(xdrs, lp));
+
+ if (xdrs->x_op == XDR_DECODE)
+ return (XDR_GETLONG(xdrs, lp));
+
+ if (xdrs->x_op == XDR_FREE)
+ return (TRUE);
+
+ return (FALSE);
+}
+
+/*
+ * XDR unsigned long integers
+ * same as xdr_long - open coded to save a proc call!
+ */
+bool_t
+xdr_u_long(xdrs, ulp)
+ register XDR *xdrs;
+ u_long *ulp;
+{
+
+ if (xdrs->x_op == XDR_DECODE)
+ return (XDR_GETLONG(xdrs, (long *)ulp));
+ if (xdrs->x_op == XDR_ENCODE)
+ return (XDR_PUTLONG(xdrs, (long *)ulp));
+ if (xdrs->x_op == XDR_FREE)
+ return (TRUE);
+ return (FALSE);
+}
+
+/*
+ * XDR short integers
+ */
+bool_t
+xdr_short(xdrs, sp)
+ register XDR *xdrs;
+ short *sp;
+{
+ long l;
+
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+ l = (long) *sp;
+ return (XDR_PUTLONG(xdrs, &l));
+
+ case XDR_DECODE:
+ if (!XDR_GETLONG(xdrs, &l)) {
+ return (FALSE);
+ }
+ *sp = (short) l;
+ return (TRUE);
+
+ case XDR_FREE:
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+/*
+ * XDR unsigned short integers
+ */
+bool_t
+xdr_u_short(xdrs, usp)
+ register XDR *xdrs;
+ u_short *usp;
+{
+ u_long l;
+
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+ l = (u_long) *usp;
+ return (XDR_PUTLONG(xdrs, &l));
+
+ case XDR_DECODE:
+ if (!XDR_GETLONG(xdrs, &l)) {
+ return (FALSE);
+ }
+ *usp = (u_short) l;
+ return (TRUE);
+
+ case XDR_FREE:
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+
+/*
+ * XDR a char
+ */
+bool_t
+xdr_char(xdrs, cp)
+ XDR *xdrs;
+ char *cp;
+{
+ int i;
+
+ i = (*cp);
+ if (!xdr_int(xdrs, &i)) {
+ return (FALSE);
+ }
+ *cp = i;
+ return (TRUE);
+}
+
+/*
+ * XDR an unsigned char
+ */
+bool_t
+xdr_u_char(xdrs, cp)
+ XDR *xdrs;
+ u_char *cp;
+{
+ u_int u;
+
+ u = (*cp);
+ if (!xdr_u_int(xdrs, &u)) {
+ return (FALSE);
+ }
+ *cp = u;
+ return (TRUE);
+}
+
+/*
+ * XDR booleans
+ */
+bool_t
+xdr_bool(xdrs, bp)
+ register XDR *xdrs;
+ bool_t *bp;
+{
+ long lb;
+
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+ lb = *bp ? XDR_TRUE : XDR_FALSE;
+ return (XDR_PUTLONG(xdrs, &lb));
+
+ case XDR_DECODE:
+ if (!XDR_GETLONG(xdrs, &lb)) {
+ return (FALSE);
+ }
+ *bp = (lb == XDR_FALSE) ? FALSE : TRUE;
+ return (TRUE);
+
+ case XDR_FREE:
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+/*
+ * XDR enumerations
+ */
+bool_t
+xdr_enum(xdrs, ep)
+ XDR *xdrs;
+ enum_t *ep;
+{
+#ifndef lint
+ enum sizecheck { SIZEVAL }; /* used to find the size of an enum */
+
+ /*
+ * enums are treated as ints
+ */
+ if (sizeof (enum sizecheck) == sizeof (long)) {
+ return (xdr_long(xdrs, (long *)ep));
+ } else if (sizeof (enum sizecheck) == sizeof (short)) {
+ return (xdr_short(xdrs, (short *)ep));
+ } else {
+ return (FALSE);
+ }
+#else
+ (void) (xdr_short(xdrs, (short *)ep));
+ return (xdr_long(xdrs, (long *)ep));
+#endif
+}
+
+/*
+ * XDR opaque data
+ * Allows the specification of a fixed size sequence of opaque bytes.
+ * cp points to the opaque object and cnt gives the byte length.
+ */
+bool_t
+xdr_opaque(xdrs, cp, cnt)
+ register XDR *xdrs;
+ caddr_t cp;
+ register u_int cnt;
+{
+ register u_int rndup;
+ static char crud[BYTES_PER_XDR_UNIT];
+
+ /*
+ * if no data we are done
+ */
+ if (cnt == 0)
+ return (TRUE);
+
+ /*
+ * round byte count to full xdr units
+ */
+ rndup = cnt % BYTES_PER_XDR_UNIT;
+ if (rndup > 0)
+ rndup = BYTES_PER_XDR_UNIT - rndup;
+
+ if (xdrs->x_op == XDR_DECODE) {
+ if (!XDR_GETBYTES(xdrs, cp, cnt)) {
+ return (FALSE);
+ }
+ if (rndup == 0)
+ return (TRUE);
+ return (XDR_GETBYTES(xdrs, crud, rndup));
+ }
+
+ if (xdrs->x_op == XDR_ENCODE) {
+ if (!XDR_PUTBYTES(xdrs, cp, cnt)) {
+ return (FALSE);
+ }
+ if (rndup == 0)
+ return (TRUE);
+ return (XDR_PUTBYTES(xdrs, xdr_zero, rndup));
+ }
+
+ if (xdrs->x_op == XDR_FREE) {
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+
+/*
+ * XDR implementation using kernel buffers
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)xdr_mem.c 1.19 87/08/11 Copyr 1984 Sun Micro";*/
+/*static char *sccsid = "from: @(#)xdr_mem.c 2.1 88/07/29 4.0 RPCSRC";*/
+/*static char *rcsid = "Id: xdr_mem.c,v 1.2.4.2 1996/06/05 02:52:04 jkh Exp";*/
+#endif
+
+/*
+ * xdr_mem.h, XDR implementation using memory buffers.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * If you have some data to be interpreted as external data representation
+ * or to be converted to external data representation in a memory buffer,
+ * then this is the package for you.
+ *
+ */
+
+
+void xdrmbuf_init __P((XDR *, KBuffer *, enum xdr_op));
+static bool_t xdrmbuf_getlong __P((XDR *, long *));
+static bool_t xdrmbuf_putlong __P((XDR *, long *));
+static bool_t xdrmbuf_getbytes __P((XDR *, caddr_t, u_int));
+static bool_t xdrmbuf_putbytes __P((XDR *, caddr_t, u_int));
+static u_int xdrmbuf_getpos __P((XDR *));
+
+static struct xdr_ops xdrmbuf_ops = {
+ xdrmbuf_getlong,
+ xdrmbuf_putlong,
+ xdrmbuf_getbytes,
+ xdrmbuf_putbytes,
+ xdrmbuf_getpos,
+ NULL,
+ NULL,
+ NULL
+};
+
+/*
+ * The procedure xdrmbuf_init initializes a stream descriptor for a
+ * kernel buffer.
+ */
+void
+xdrmbuf_init(xdrs, m, op)
+ register XDR *xdrs;
+ KBuffer *m;
+ enum xdr_op op;
+{
+
+ xdrs->x_op = op;
+ xdrs->x_ops = &xdrmbuf_ops;
+ xdrs->x_base = (caddr_t)m;
+ KB_DATASTART(m, xdrs->x_private, caddr_t);
+ xdrs->x_handy = KB_LEN(m);
+}
+
+static bool_t
+xdrmbuf_getlong(xdrs, lp)
+ register XDR *xdrs;
+ long *lp;
+{
+
+ /*
+ * See if long is contained in this buffer
+ */
+ if ((xdrs->x_handy -= sizeof(long)) < 0) {
+ register KBuffer *m;
+
+ /*
+ * We (currently) don't allow a long to span a buffer
+ */
+ if (xdrs->x_handy != -sizeof(long)) {
+ printf("xdrmbuf_getlong: data spans buffers\n");
+ return (FALSE);
+ }
+
+ /*
+ * Try to move to a chained buffer
+ */
+ if ((m = (KBuffer *)(xdrs->x_base)) != NULL) {
+ m = KB_NEXT(m);
+ xdrs->x_base = (caddr_t)m;
+ }
+ if (m) {
+ /*
+ * Setup new buffer's info
+ */
+ KB_DATASTART(m, xdrs->x_private, caddr_t);
+ if ((xdrs->x_handy = KB_LEN(m) - sizeof(long)) < 0) {
+ printf("xdrmbuf_getlong: short buffer\n");
+ return (FALSE);
+ }
+ } else {
+ /*
+ * No more buffers
+ */
+ return (FALSE);
+ }
+ }
+
+ /*
+ * Return the long value
+ */
+ *lp = (long)ntohl((u_long)(*((long *)(xdrs->x_private))));
+
+ /*
+ * Advance the data stream
+ */
+ xdrs->x_private += sizeof(long);
+ return (TRUE);
+}
+
+static bool_t
+xdrmbuf_putlong(xdrs, lp)
+ register XDR *xdrs;
+ long *lp;
+{
+
+ /*
+ * See if long will fit in this buffer
+ */
+ if ((xdrs->x_handy -= sizeof(long)) < 0) {
+ register KBuffer *m;
+
+ /*
+ * We (currently) don't allow a long to span a buffer
+ */
+ if (xdrs->x_handy != -sizeof(long)) {
+ printf("xdrmbuf_putlong: data spans buffers\n");
+ return (FALSE);
+ }
+
+ /*
+ * Try to move to a chained buffer
+ */
+ if ((m = (KBuffer *)(xdrs->x_base)) != NULL) {
+ m = KB_NEXT(m);
+ xdrs->x_base = (caddr_t)m;
+ }
+ if (m) {
+ /*
+ * Setup new buffer's info
+ */
+ KB_DATASTART(m, xdrs->x_private, caddr_t);
+ if ((xdrs->x_handy = KB_LEN(m) - sizeof(long)) < 0) {
+ printf("xdrmbuf_putlong: short buffer\n");
+ return (FALSE);
+ }
+ } else {
+ /*
+ * No more buffers
+ */
+ return (FALSE);
+ }
+ }
+
+ /*
+ * Store the long value into our buffer
+ */
+ *(long *)xdrs->x_private = (long)htonl((u_long)(*lp));
+
+ /*
+ * Advance the data stream
+ */
+ xdrs->x_private += sizeof(long);
+ return (TRUE);
+}
+
+static bool_t
+xdrmbuf_getbytes(xdrs, addr, len)
+ register XDR *xdrs;
+ caddr_t addr;
+ register u_int len;
+{
+
+ while (len > 0) {
+ u_int copy;
+
+ if (xdrs->x_handy <= 0) {
+ register KBuffer *m;
+
+ /*
+ * No data in current buffer, move to a chained buffer
+ */
+ if ((m = (KBuffer *)(xdrs->x_base)) != NULL) {
+ m = KB_NEXT(m);
+ xdrs->x_base = (caddr_t)m;
+ }
+ if (m) {
+ /*
+ * Setup new buffer's info
+ */
+ KB_DATASTART(m, xdrs->x_private, caddr_t);
+ xdrs->x_handy = KB_LEN(m);
+ } else {
+ /*
+ * No more buffers
+ */
+ return (FALSE);
+ }
+ }
+
+ /*
+ * Copy from buffer to user's space
+ */
+ copy = MIN(len, xdrs->x_handy);
+ KM_COPY(xdrs->x_private, addr, copy);
+
+ /*
+ * Update data stream controls
+ */
+ xdrs->x_private += copy;
+ xdrs->x_handy -= copy;
+ addr += copy;
+ len -= copy;
+ }
+ return (TRUE);
+}
+
+static bool_t
+xdrmbuf_putbytes(xdrs, addr, len)
+ register XDR *xdrs;
+ caddr_t addr;
+ register u_int len;
+{
+
+ while (len > 0) {
+ u_int copy;
+
+ if (xdrs->x_handy <= 0) {
+ register KBuffer *m;
+
+ /*
+ * No data in current buffer, move to a chained buffer
+ */
+ if ((m = (KBuffer *)(xdrs->x_base)) != NULL) {
+ m = KB_NEXT(m);
+ xdrs->x_base = (caddr_t)m;
+ }
+ if (m) {
+ /*
+ * Setup new buffer's info
+ */
+ KB_DATASTART(m, xdrs->x_private, caddr_t);
+ xdrs->x_handy = KB_LEN(m);
+ } else {
+ /*
+ * No more buffers
+ */
+ return (FALSE);
+ }
+ }
+
+ /*
+ * Copy from user's space into buffer
+ */
+ copy = MIN(len, xdrs->x_handy);
+ KM_COPY(addr, xdrs->x_private, copy);
+
+ /*
+ * Update data stream controls
+ */
+ xdrs->x_private += copy;
+ xdrs->x_handy -= copy;
+ addr += copy;
+ len -= copy;
+ }
+ return (TRUE);
+}
+
+static u_int
+xdrmbuf_getpos(xdrs)
+ register XDR *xdrs;
+{
+
+ return ((u_int)xdrs->x_private - (u_int)xdrs->x_base);
+}
+
+#endif /* !defined(sun) */
+
diff --git a/sys/netatm/spans/spans_msg.c b/sys/netatm/spans/spans_msg.c
new file mode 100644
index 0000000..0dc5df9
--- /dev/null
+++ b/sys/netatm/spans/spans_msg.c
@@ -0,0 +1,1633 @@
+/*
+ *
+ * ===================================
+ * 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: spans_msg.c,v 1.8 1998/08/26 23:29:09 mks Exp $
+ *
+ */
+
+/*
+ * SPANS Signalling Manager
+ * ---------------------------
+ *
+ * SPANS signalling message processing.
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: spans_msg.c,v 1.8 1998/08/26 23:29:09 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <rpc/rpc.h>
+#include "spans_xdr.h"
+#include <netatm/spans/spans_var.h>
+
+/*
+ * External functions
+ */
+void xdrmbuf_init __P((XDR *, KBuffer *, enum xdr_op));
+
+/*
+ * Local functions
+ */
+static void spans_host_link __P((struct spans *, long));
+static void spans_status_ind __P((struct spans *, spans_msg *));
+static void spans_status_rsp __P((struct spans *, spans_msg *));
+static void spans_open_req __P((struct spans *, spans_msg *));
+static void spans_open_rsp __P((struct spans *, spans_msg *));
+static void spans_close_req __P((struct spans *, spans_msg *));
+static void spans_close_rsp __P((struct spans *, spans_msg *));
+static void spans_multi_req __P((struct spans *, spans_msg *));
+static void spans_add_req __P((struct spans *, spans_msg *));
+static void spans_join_req __P((struct spans *, spans_msg *));
+static void spans_leave_req __P((struct spans *, spans_msg *));
+static void spans_vcir_ind __P((struct spans *, spans_msg *));
+static void spans_query_req __P((struct spans *, spans_msg *));
+
+
+/*
+ * Called to set status when a status message comes in from a host
+ * connected back-to-back with us. Check the epoch and, if it has
+ * changed, set the appropriate state and save updated state
+ * information.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance block
+ * host_epoch epoch of host at far end of link
+ *
+ * Returns:
+ * 0 message sent OK
+ * errno error encountered
+ *
+ */
+static void
+spans_host_link(spp, host_epoch)
+ struct spans *spp;
+ long host_epoch;
+{
+ struct atm_pif *pip = spp->sp_pif;
+
+ /*
+ * There's a host at the other end of the link. If its
+ * epoch has changed, clean up our state and save the
+ * new information.
+ */
+ if (spp->sp_s_epoch != host_epoch) {
+ spp->sp_s_epoch = host_epoch;
+ spans_switch_reset(spp, SPANS_UNI_UP);
+ spp->sp_addr.address_format = T_ATM_SPANS_ADDR;
+ spp->sp_addr.address_length = sizeof(spans_addr);
+ KM_COPY(&pip->pif_macaddr.ma_data[2],
+ &spp->sp_addr.address[4],
+ 4);
+ log(LOG_INFO,
+ "spans: using SPANS address of %s on interface %s%d\n",
+ spans_addr_print((spans_addr *)spp->sp_addr.address),
+ pip->pif_name,
+ pip->pif_unit);
+ }
+}
+
+/*
+ * Send a SPANS signalling message
+ *
+ * Called to send a SPANS message. This routine gets a buffer, performs
+ * XDR processing, and hands the message to the AAL for transmission.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance block
+ * msg pointer to status message
+ *
+ * Returns:
+ * 0 message sent OK
+ * errno error encountered
+ *
+ */
+int
+spans_send_msg(spp, msg)
+ struct spans *spp;
+ spans_msg *msg;
+{
+ int err = 0;
+ KBuffer *m;
+ XDR xdrs;
+
+#ifdef NOTDEF
+ ATM_DEBUG2("spans_send_msg: msg=0x%x, type=%d\n", msg,
+ msg->sm_type);
+ if (msg->sm_type != SPANS_STAT_REQ &&
+ msg->sm_type != SPANS_STAT_IND &&
+ msg->sm_type != SPANS_STAT_RSP) {
+ printf("spans_send_msg: sending ");
+ spans_print_msg(msg);
+ }
+#endif
+
+ /*
+ * If the signalling channel has been closed, don't do anything
+ */
+ if (!spp->sp_conn)
+ return(ECONNABORTED);
+
+ /*
+ * Get a buffer
+ */
+ KB_ALLOCPKT(m, sizeof(spans_msg), KB_F_NOWAIT, KB_T_DATA);
+ if (m == NULL) {
+ /* No buffer available */
+ return(ENOBUFS);
+ }
+
+ /*
+ * Convert message to network order
+ */
+ KB_LEN(m) = KB_BFRLEN(m);
+ xdrmbuf_init(&xdrs, m, XDR_ENCODE);
+ if (!xdr_spans_msg(&xdrs, msg)) {
+ log(LOG_ERR, "spans_send_msg: XDR encode failed\n");
+ KB_LEN(m) = XDR_GETPOS(&xdrs);
+ spans_dump_buffer(m);
+ KB_FREEALL(m);
+ return(EIO);
+ }
+ KB_LEN(m) = XDR_GETPOS(&xdrs);
+
+ /*
+ * Send the message
+ */
+ err = atm_cm_cpcs_data(spp->sp_conn, m);
+ if (err)
+ KB_FREEALL(m);
+
+ return(err);
+}
+
+
+/*
+ * Send an open request
+ *
+ * Build and send an open request.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance block
+ * svp pointer to VCCB for which the request is being sent
+ *
+ * Returns:
+ * none
+ *
+ */
+int
+spans_send_open_req(spp, svp)
+ struct spans *spp;
+ struct spans_vccb *svp;
+{
+ spans_msg *req;
+ int err = 0;
+
+ ATM_DEBUG1("spans_send_open_req: svp=0x%x\n", svp);
+
+ /*
+ * Get memory for a request message
+ */
+ req = (spans_msg *)atm_allocate(&spans_msgpool);
+ if (req == NULL) {
+ err = ENOBUFS;
+ goto done;
+ }
+
+ /*
+ * Fill in the request
+ */
+ req->sm_vers = SPANS_VERS_1_0;
+ req->sm_type = SPANS_OPEN_REQ;
+ req->sm_open_req.opreq_conn = svp->sv_conn;
+ req->sm_open_req.opreq_aal = svp->sv_spans_aal;
+ req->sm_open_req.opreq_desrsrc = svp->sv_spans_qos;
+ req->sm_open_req.opreq_minrsrc.rsc_peak = 0;
+ req->sm_open_req.opreq_minrsrc.rsc_mean = 0;
+ req->sm_open_req.opreq_minrsrc.rsc_burst = 0;
+ req->sm_open_req.opreq_vpvc.vpf_valid = FALSE;
+
+ /*
+ * Send the request
+ */
+ err = spans_send_msg(spp, req);
+ atm_free(req);
+
+done:
+ return(err);
+}
+
+
+/*
+ * Send an open response
+ *
+ * Build and send a response to an open request or open indication.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance block
+ * svp pointer to VCCB for which the response is being sent
+ * result result code to include in the response
+ *
+ * Returns:
+ * none
+ *
+ */
+int
+spans_send_open_rsp(spp, svp, result)
+ struct spans *spp;
+ struct spans_vccb *svp;
+ spans_result result;
+{
+ spans_msg *rsp;
+ int rc;
+
+ ATM_DEBUG2("spans_send_open_rsp: svp=0x%x, result=%d\n", svp,
+ result);
+
+ /*
+ * Get memory for a response message
+ */
+ rsp = (spans_msg *)atm_allocate(&spans_msgpool);
+ if (rsp == NULL)
+ return(ENOBUFS);
+
+ /*
+ * Fill in the response
+ */
+ rsp->sm_vers = SPANS_VERS_1_0;
+ rsp->sm_type = SPANS_OPEN_RSP;
+ rsp->sm_open_rsp.oprsp_conn = svp->sv_conn;
+ rsp->sm_open_rsp.oprsp_result = result;
+ rsp->sm_open_rsp.oprsp_rsrc = svp->sv_spans_qos;
+ rsp->sm_open_rsp.oprsp_vpvc =
+ SPANS_PACK_VPIVCI(svp->sv_vpi, svp->sv_vci);
+
+ /*
+ * Send the response
+ */
+ rc = spans_send_msg(spp, rsp);
+ atm_free(rsp);
+
+ return(rc);
+}
+
+
+/*
+ * Send a close request
+ *
+ * Called to send a close request.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance block
+ * svp pointer to VCCB for which the close is being sent
+ *
+ * Returns:
+ * none
+ *
+ */
+int
+spans_send_close_req(spp, svp)
+ struct spans *spp;
+ struct spans_vccb *svp;
+{
+ spans_msg *req;
+ int err = 0;
+
+ ATM_DEBUG1("spans_send_close_req: svp=0x%x\n", svp);
+
+ /*
+ * Get memory for a close request
+ */
+ req = (spans_msg *)atm_allocate(&spans_msgpool);
+ if (req == NULL) {
+ err = ENOBUFS;
+ goto done;
+ }
+
+ /*
+ * Fill in the request
+ */
+ req->sm_vers = SPANS_VERS_1_0;
+ if (svp->sv_type & VCC_OUT) {
+ req->sm_type = SPANS_CLOSE_REQ;
+ } else if (svp->sv_type & VCC_IN) {
+ req->sm_type = SPANS_RCLOSE_REQ;
+ } else {
+ err = EINVAL;
+ ATM_DEBUG1(
+ "spans_send_close_req: invalid VCCB type 0x%x\n",
+ svp->sv_type);
+ goto done;
+ }
+ req->sm_close_req.clreq_conn = svp->sv_conn;
+
+ /*
+ * Send the close request
+ */
+ err = spans_send_msg(spp, req);
+
+done:
+ if (req)
+ atm_free(req);
+
+ return(err);
+}
+
+
+
+/*
+ * Process a status indication or status request
+ *
+ * Called when a status indication or status request is received.
+ * Processing will be based on the current SPANS state.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance block
+ * msg pointer to the status message
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+spans_status_ind(spp, msg)
+ struct spans *spp;
+ spans_msg *msg;
+{
+ spans_msg *rsp_msg;
+ struct atm_pif *pip = spp->sp_pif;
+
+ /*
+ * Reset the probe count.
+ */
+ spp->sp_probe_ct = 0;
+
+ switch (spp->sp_state) {
+ case SPANS_PROBE:
+ /*
+ * Interface just came up, update signalling state
+ */
+ spp->sp_state = SPANS_ACTIVE;
+ break;
+
+ case SPANS_ACTIVE:
+ break;
+
+ default:
+ log(LOG_ERR, "spans: received status msg in state %d\n",
+ spp->sp_state);
+ }
+
+ /*
+ * Process the message
+ */
+ switch (msg->sm_type) {
+
+ case SPANS_STAT_REQ:
+ /*
+ * Handle a request from a host at the other end of
+ * the link.
+ */
+ spans_host_link(spp, msg->sm_stat_req.streq_es_epoch);
+ break;
+
+ case SPANS_STAT_IND:
+
+ /*
+ * There's a switch at the other end of the link. If
+ * its epoch has changed, reset the SPANS state and save
+ * the new information.
+ */
+ if (spp->sp_s_epoch !=
+ msg->sm_stat_ind.stind_sw_epoch) {
+ spans_switch_reset(spp, SPANS_UNI_UP);
+ spp->sp_s_epoch =
+ msg->sm_stat_ind.stind_sw_epoch;
+ spp->sp_addr.address_format = T_ATM_SPANS_ADDR;
+ spp->sp_addr.address_length =
+ sizeof(spans_addr);
+ spans_addr_copy(&msg->sm_stat_ind.stind_es_addr,
+ spp->sp_addr.address);
+ log(LOG_INFO,
+ "spans: received SPANS address %s from switch for interface %s%d\n",
+ spans_addr_print((spans_addr *)spp->sp_addr.address),
+ pip->pif_name,
+ pip->pif_unit);
+ }
+ break;
+
+ default:
+ ATM_DEBUG1("spans_status_ind: Invalid message type %d\n",
+ msg->sm_type);
+ return;
+ }
+
+ /*
+ * Respond to the status request or indication with a
+ * status response
+ */
+ rsp_msg = (spans_msg *)atm_allocate(&spans_msgpool);
+ if (rsp_msg == NULL)
+ return;
+ rsp_msg->sm_vers = SPANS_VERS_1_0;
+ rsp_msg->sm_type = SPANS_STAT_RSP;
+ rsp_msg->sm_stat_rsp.strsp_es_epoch = spp->sp_h_epoch;
+ spans_addr_copy(spp->sp_addr.address,
+ &rsp_msg->sm_stat_rsp.strsp_es_addr);
+ spans_send_msg(spp, rsp_msg);
+ atm_free(rsp_msg);
+}
+
+
+
+/*
+ * Process a status response
+ *
+ * Called when a status response is received.
+ * Processing will be based on the current SPANS state.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance block
+ * msg pointer to the status response message
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+spans_status_rsp(spp, msg)
+ struct spans *spp;
+ spans_msg *msg;
+{
+
+ /*
+ * Reset the probe count.
+ */
+ spp->sp_probe_ct = 0;
+
+ switch (spp->sp_state) {
+ case SPANS_PROBE:
+ /*
+ * Interface just came up, update signalling state
+ */
+ spp->sp_state = SPANS_ACTIVE;
+ break;
+
+ case SPANS_ACTIVE:
+ break;
+
+ default:
+ log(LOG_ERR, "spans: received status msg in state %d\n",
+ spp->sp_state);
+ }
+
+ /*
+ * Process the message
+ */
+ spans_host_link(spp, msg->sm_stat_req.streq_es_epoch);
+}
+
+
+/*
+ * Process an open indication or open request
+ *
+ * Called when an open indication or open request is received.
+ * Processing will be based on the state of the requested connection.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance block
+ * msg pointer to the open message
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+spans_open_req(spp, msg)
+ struct spans *spp;
+ spans_msg *msg;
+{
+ spans_result result = SPANS_OK;
+ spans_msg *rsp_msg;
+ struct spans_vccb *svp = NULL;
+ struct atm_pif *pip;
+ spans_vpvc vpvc;
+ int err = 0, vpi, vci;
+ Aal_t aal;
+ Atm_attributes call_attrs;
+
+ ATM_DEBUG2("spans_open_req: spp=0x%x, msg=0x%x\n", spp, msg);
+
+ /*
+ * See if the connection is new
+ */
+ if (svp = spans_find_conn(spp, &msg->sm_open_req.opreq_conn)) {
+ /*
+ * We already have a VCCB that matches the connection in
+ * the request
+ */
+ vpi = SPANS_EXTRACT_VPI(msg->sm_open_req.opreq_vpvc.vpf_vpvc);
+ vci = SPANS_EXTRACT_VCI(msg->sm_open_req.opreq_vpvc.vpf_vpvc);
+ if (msg->sm_open_req.opreq_aal == svp->sv_spans_aal &&
+ (!msg->sm_open_req.opreq_vpvc.vpf_valid ||
+ (vpi == svp->sv_vpi &&
+ vci == svp->sv_vci))) {
+ /*
+ * VCCB already exists, process depending on
+ * state
+ */
+ switch (svp->sv_sstate) {
+ case SPANS_VC_R_POPEN:
+ /* I'm still thinking about it */
+ return;
+ case SPANS_VC_OPEN:
+ /* Retransmit the open_rsp */
+ break;
+ case SPANS_VC_POPEN:
+ case SPANS_VC_CLOSE:
+ case SPANS_VC_ABORT:
+ ATM_DEBUG0("spans_open_req: bad VCCB state\n");
+ result = SPANS_FAIL;
+ break;
+ }
+ } else {
+ /*
+ * VCCB is for same connection, but other
+ * parameters don't match
+ */
+ ATM_DEBUG0("spans_open_req: VCCB confusion\n");
+ result = SPANS_FAIL;
+ }
+ svp = NULL;
+ goto response;
+ }
+
+ /*
+ * Verify that the request is for our ATM addres
+ */
+ if (spans_addr_cmp(spp->sp_addr.address,
+ &msg->sm_open_req.opreq_conn.con_dst)) {
+ ATM_DEBUG0("spans_open_req: bad destination\n");
+ result = SPANS_BADDEST;
+ goto response;
+ }
+
+ /*
+ * See if we recognize the specified AAL
+ */
+ if (!spans_get_local_aal(msg->sm_open_req.opreq_aal, &aal)) {
+ ATM_DEBUG0("spans_open_req: bad AAL\n");
+ result = SPANS_FAIL;
+ goto response;
+ }
+
+ /*
+ * Should verify that we can handle requested connection QOS
+ */
+
+ /*
+ * Select a VPI/VCI for the new connection
+ */
+ if (msg->sm_open_req.opreq_vpvc.vpf_valid) {
+ /*
+ * Requestor asked for a certain VPI/VCI. Make sure we
+ * aren't already using the pair that was asked for.
+ */
+ vpi = SPANS_EXTRACT_VPI(msg->sm_open_req.opreq_vpvc.vpf_vpvc);
+ vci = SPANS_EXTRACT_VCI(msg->sm_open_req.opreq_vpvc.vpf_vpvc);
+ if (spans_find_vpvc(spp, vci, vpi, VCC_IN)) {
+ ATM_DEBUG0("spans_open_req: VPI, VCI busy\n");
+ result = SPANS_NOVPVC;
+ goto response;
+ }
+ vpvc = msg->sm_open_req.opreq_vpvc.vpf_vpvc;
+ } else {
+ /*
+ * Allocate a VPI/VCI for this end of the VCC
+ */
+ vpvc = spans_alloc_vpvc(spp);
+ if (vpvc == 0) {
+ ATM_DEBUG0("spans_open_req: no VPI, VCI available\n");
+ result = SPANS_NOVPVC;
+ goto response;
+ }
+ }
+
+ /*
+ * Get a new VCCB for the connection
+ */
+ svp = (struct spans_vccb *)atm_allocate(&spans_vcpool);
+ if (svp == NULL) {
+ ATM_DEBUG0("spans_open_req: VCCB pool empty\n");
+ result = SPANS_NORSC;
+ goto response;
+ }
+
+ /*
+ * Find the physical interface structure
+ */
+ pip = spp->sp_pif;
+
+ /*
+ * Fill in the VCCB fields that we can at this point
+ */
+ svp->sv_type = VCC_SVC | VCC_IN;
+ svp->sv_proto = ATM_SIG_SPANS;
+ svp->sv_sstate = SPANS_VC_R_POPEN;
+ svp->sv_ustate = VCCU_POPEN;
+ svp->sv_pif = pip;
+ svp->sv_nif = pip->pif_nif;
+ svp->sv_conn = msg->sm_open_req.opreq_conn;
+ svp->sv_spans_qos = msg->sm_open_req.opreq_desrsrc;
+ svp->sv_spans_aal = msg->sm_open_req.opreq_aal;
+ svp->sv_tstamp = time_second;
+
+ svp->sv_vpi = SPANS_EXTRACT_VPI(vpvc);
+ svp->sv_vci = SPANS_EXTRACT_VCI(vpvc);
+
+ /*
+ * Put the VCCB on the SPANS queue
+ */
+ ENQUEUE(svp, struct spans_vccb, sv_sigelem, spp->sp_vccq);
+
+ /*
+ * Set up the ATM attributes block
+ */
+ KM_ZERO(&call_attrs, sizeof(call_attrs));
+ call_attrs.nif = svp->sv_nif;
+ call_attrs.api = CMAPI_CPCS;
+
+ call_attrs.aal.tag = T_ATM_PRESENT;
+ call_attrs.aal.type = aal;
+ switch(aal) {
+ case ATM_AAL3_4:
+ call_attrs.aal.v.aal4.forward_max_SDU_size =
+ ATM_NIF_MTU;
+ call_attrs.aal.v.aal4.backward_max_SDU_size =
+ ATM_NIF_MTU;
+ call_attrs.aal.v.aal4.SSCS_type =
+ T_ATM_NULL;
+ call_attrs.aal.v.aal4.mid_low = 0;
+ call_attrs.aal.v.aal4.mid_high = 1023;
+ break;
+ case ATM_AAL5:
+ call_attrs.aal.v.aal5.forward_max_SDU_size =
+ ATM_NIF_MTU;
+ call_attrs.aal.v.aal5.backward_max_SDU_size =
+ ATM_NIF_MTU;
+ call_attrs.aal.v.aal5.SSCS_type =
+ T_ATM_NULL;
+ break;
+ }
+
+ call_attrs.traffic.tag = T_ATM_PRESENT;
+ call_attrs.traffic.v.forward.PCR_high_priority = T_ATM_ABSENT;
+ call_attrs.traffic.v.forward.PCR_all_traffic =
+ msg->sm_open_req.opreq_desrsrc.rsc_peak *
+ 1000 / 53;
+ call_attrs.traffic.v.forward.SCR_high_priority = T_ATM_ABSENT;
+ call_attrs.traffic.v.forward.SCR_all_traffic = T_ATM_ABSENT;
+ call_attrs.traffic.v.forward.MBS_high_priority = T_ATM_ABSENT;
+ call_attrs.traffic.v.forward.MBS_all_traffic = T_ATM_ABSENT;
+ call_attrs.traffic.v.forward.tagging = T_NO;
+ call_attrs.traffic.v.backward.PCR_high_priority = T_ATM_ABSENT;
+ call_attrs.traffic.v.backward.PCR_all_traffic =
+ call_attrs.traffic.v.forward.PCR_all_traffic;
+ call_attrs.traffic.v.backward.SCR_high_priority = T_ATM_ABSENT;
+ call_attrs.traffic.v.backward.SCR_all_traffic = T_ATM_ABSENT;
+ call_attrs.traffic.v.backward.MBS_high_priority = T_ATM_ABSENT;
+ call_attrs.traffic.v.backward.MBS_all_traffic = T_ATM_ABSENT;
+ call_attrs.traffic.v.backward.tagging = T_NO;
+ call_attrs.traffic.v.best_effort = T_YES;
+
+ call_attrs.bearer.tag = T_ATM_PRESENT;
+ call_attrs.bearer.v.bearer_class = T_ATM_CLASS_X;
+ call_attrs.bearer.v.traffic_type = T_ATM_NULL;
+ call_attrs.bearer.v.timing_requirements = T_ATM_NULL;
+ call_attrs.bearer.v.clipping_susceptibility = T_NO;
+ call_attrs.bearer.v.connection_configuration = T_ATM_1_TO_1;
+
+
+ call_attrs.bhli.tag = T_ATM_ABSENT;
+ call_attrs.blli.tag_l2 = T_ATM_ABSENT;
+ call_attrs.blli.tag_l3 = T_ATM_ABSENT;
+ call_attrs.llc.tag = T_ATM_ABSENT;
+
+ call_attrs.called.tag = T_ATM_PRESENT;
+ spans_addr_copy(&msg->sm_open_req.opreq_conn.con_dst,
+ call_attrs.called.addr.address);
+ call_attrs.called.addr.address_format = T_ATM_SPANS_ADDR;
+ call_attrs.called.addr.address_length = sizeof(spans_addr);
+ call_attrs.called.subaddr.address_format = T_ATM_ABSENT;
+ call_attrs.called.subaddr.address_length = 0;
+
+ call_attrs.calling.tag = T_ATM_PRESENT;
+ spans_addr_copy(&msg->sm_open_req.opreq_conn.con_src,
+ call_attrs.calling.addr.address);
+ call_attrs.calling.addr.address_format = T_ATM_SPANS_ADDR;
+ call_attrs.calling.addr.address_length = sizeof(spans_addr);
+ call_attrs.calling.subaddr.address_format = T_ATM_ABSENT;
+ call_attrs.calling.subaddr.address_length = 0;
+
+ call_attrs.qos.tag = T_ATM_PRESENT;
+ call_attrs.qos.v.coding_standard = T_ATM_NETWORK_CODING;
+ call_attrs.qos.v.forward.qos_class = T_ATM_QOS_CLASS_0;
+ call_attrs.qos.v.backward.qos_class = T_ATM_QOS_CLASS_0;
+
+ call_attrs.transit.tag = T_ATM_ABSENT;
+ call_attrs.cause.tag = T_ATM_ABSENT;
+
+ /*
+ * Notify the connection manager that it has a new channel
+ */
+ err = atm_cm_incoming((struct vccb *)svp, &call_attrs);
+ if (err) {
+ ATM_DEBUG0("spans_open_req: atm_cm_incoming returned error\n");
+ result = SPANS_FAIL;
+ goto response;
+ }
+
+ /*
+ * Wait for the connection recipient to issue an accept
+ */
+ return;
+
+response:
+ /*
+ * Clean up the VCCB and the atm_conn block if we got them
+ */
+ if (svp) {
+ DEQUEUE(svp, struct spans_vccb, sv_sigelem,
+ spp->sp_vccq);
+ atm_free(svp);
+ }
+
+ /*
+ * Some problem was detected with the request. Send a SPANS
+ * message rejecting the connection.
+ */
+ rsp_msg = (spans_msg *) atm_allocate(&spans_msgpool);
+ if (rsp_msg == NULL)
+ return;
+
+ /*
+ * Fill out the response
+ */
+ rsp_msg->sm_vers = SPANS_VERS_1_0;
+ rsp_msg->sm_type = SPANS_OPEN_RSP;
+ rsp_msg->sm_open_rsp.oprsp_conn = msg->sm_open_req.opreq_conn;
+ rsp_msg->sm_open_rsp.oprsp_result = result;
+ rsp_msg->sm_open_rsp.oprsp_vpvc = 0;
+
+ /*
+ * Send the Open Response
+ */
+ spans_send_msg(spp, rsp_msg);
+ atm_free(rsp_msg);
+}
+
+
+/*
+ * Process an open response or open confirmation
+ *
+ * Called when an open response or open confirmation is received.
+ * Processing will be based on the state of the requested connection and
+ * the status returned.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance block
+ * msg pointer to the open response or confirmation message
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+spans_open_rsp(spp, msg)
+ struct spans *spp;
+ spans_msg *msg;
+{
+ struct spans_vccb *svp;
+
+ ATM_DEBUG2("spans_open_rsp: spp=0x%x, msg=0x%x\n", spp, msg);
+
+ /*
+ * Locate the VCCB for the connection
+ */
+ svp = spans_find_conn(spp, &msg->sm_open_rsp.oprsp_conn);
+ if (svp == NULL)
+ return;
+
+ /*
+ * Check the connection state
+ */
+ if ((svp->sv_sstate != SPANS_VC_POPEN &&
+ svp->sv_sstate != SPANS_VC_R_POPEN) ||
+ svp->sv_ustate != VCCU_POPEN) {
+ ATM_DEBUG2(
+ "spans_open_rsp: invalid VCCB state, sstate=%d, ustate=%d\n",
+ svp->sv_sstate, svp->sv_ustate);
+ return;
+ }
+
+ /*
+ * Cancel the retransmission timer
+ */
+ SPANS_VC_CANCEL((struct vccb *) svp);
+
+ /*
+ * Check the result
+ */
+ switch (msg->sm_open_rsp.oprsp_result) {
+
+ case SPANS_OK:
+ /*
+ * Save the assigned VPI and VCI
+ */
+ svp->sv_vpi = SPANS_EXTRACT_VPI(msg->sm_open_rsp.oprsp_vpvc);
+ svp->sv_vci = SPANS_EXTRACT_VCI(msg->sm_open_rsp.oprsp_vpvc);
+
+ /*
+ * Update the VCC state and notify the VCC owner
+ */
+ svp->sv_sstate = SPANS_VC_OPEN;
+ svp->sv_ustate = VCCU_OPEN;
+ svp->sv_tstamp = time_second;
+ atm_cm_connected(svp->sv_connvc);
+ break;
+
+ case SPANS_FAIL:
+ case SPANS_NOVPVC:
+ case SPANS_NORSC:
+ case SPANS_BADDEST:
+ /*
+ * Close out the VCCB and notify the user
+ */
+ svp->sv_sstate = SPANS_VC_FREE;
+ svp->sv_ustate = VCCU_CLOSED;
+ svp->sv_connvc->cvc_attr.cause.tag = T_ATM_PRESENT;
+ svp->sv_connvc->cvc_attr.cause.v.coding_standard =
+ T_ATM_ITU_CODING;
+ svp->sv_connvc->cvc_attr.cause.v.location =
+ T_ATM_LOC_USER;
+ svp->sv_connvc->cvc_attr.cause.v.cause_value =
+ T_ATM_CAUSE_CALL_REJECTED;
+ KM_ZERO(svp->sv_connvc->cvc_attr.cause.v.diagnostics,
+ sizeof(svp->sv_connvc->cvc_attr.cause.v.diagnostics));
+ atm_cm_cleared(svp->sv_connvc);
+ break;
+
+ default:
+ log(LOG_ERR, "spans: unknown result %d in open rsp\n",
+ msg->sm_open_rsp.oprsp_result);
+ break;
+ }
+}
+
+
+/*
+ * Process a close request from the network
+ *
+ * Called when a close request, close indication, rclose request, or
+ * rclose indication is received. Processing will be based on the
+ * state of the connection.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance block
+ * msg pointer to the close request message
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+spans_close_req(spp, msg)
+ struct spans *spp;
+ spans_msg *msg;
+{
+ struct spans_vccb *svp;
+ spans_result result;
+ spans_msg *rsp_msg;
+ u_char outstate;
+ Atm_connvc *cvp;
+
+ ATM_DEBUG2("spans_close_req: spp=0x%x, msg=0x%x\n", spp, msg);
+
+ /*
+ * Locate the VCCB for the connection
+ */
+ svp = spans_find_conn(spp, &msg->sm_close_req.clreq_conn);
+ if (svp == NULL) {
+ result = SPANS_BADDEST;
+ goto response;
+ }
+
+ /*
+ * Check the connection type
+ */
+ if (!(svp->sv_type & VCC_SVC)) {
+ result = SPANS_FAIL;
+ goto response;
+ }
+
+ /*
+ * Check the connection state
+ */
+ switch (svp->sv_sstate) {
+ case SPANS_VC_OPEN:
+ case SPANS_VC_R_POPEN:
+ case SPANS_VC_POPEN:
+ /*
+ * VCC is open or opening--continue
+ */
+ break;
+ case SPANS_VC_CLOSE:
+ case SPANS_VC_FREE:
+ case SPANS_VC_ABORT:
+ /*
+ * We're already closing--give a response, since this
+ * is probably a retransmission
+ */
+ result = SPANS_OK;
+ goto response;
+ case SPANS_VC_NULL:
+ result = SPANS_FAIL;
+ goto response;
+ }
+
+ /*
+ * Cancel the retransmission timer
+ */
+ SPANS_VC_CANCEL((struct vccb *) svp);
+
+ /*
+ * Close out the VCCB and notify the user
+ */
+ outstate = svp->sv_sstate;
+ svp->sv_ustate = VCCU_CLOSED;
+ svp->sv_sstate = SPANS_VC_FREE;
+ cvp = svp->sv_connvc;
+ switch (outstate) {
+ case SPANS_VC_R_POPEN:
+ spans_free((struct vccb *)svp);
+ /* FALLTHRU */
+
+ case SPANS_VC_POPEN:
+ case SPANS_VC_OPEN:
+ cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
+ cvp->cvc_attr.cause.v.coding_standard =
+ T_ATM_ITU_CODING;
+ cvp->cvc_attr.cause.v.location = T_ATM_LOC_USER;
+ cvp->cvc_attr.cause.v.cause_value =
+ T_ATM_CAUSE_NORMAL_CALL_CLEARING;
+ KM_ZERO(cvp->cvc_attr.cause.v.diagnostics,
+ sizeof(cvp->cvc_attr.cause.v.diagnostics));
+ atm_cm_cleared(svp->sv_connvc);
+ break;
+ }
+
+ result = SPANS_OK;
+
+response:
+ /*
+ * Respond to the SPANS_CLOSE_IND with a SPANS_CLOSE_RSP
+ */
+ rsp_msg = (spans_msg *)atm_allocate(&spans_msgpool);
+ if (rsp_msg == NULL)
+ return;
+ rsp_msg->sm_vers = SPANS_VERS_1_0;
+ if (msg->sm_type == SPANS_RCLOSE_REQ ||
+ msg->sm_type == SPANS_RCLOSE_IND) {
+ rsp_msg->sm_type = SPANS_RCLOSE_RSP;
+ } else {
+ rsp_msg->sm_type = SPANS_CLOSE_RSP;
+ }
+ rsp_msg->sm_close_rsp.clrsp_conn = msg->sm_close_req.clreq_conn;
+ rsp_msg->sm_close_rsp.clrsp_result = result;
+ spans_send_msg(spp, rsp_msg);
+ atm_free(rsp_msg);
+}
+
+
+/*
+ * Process a close response or close confirmation
+ *
+ * Called when an close response or close confirmation is received.
+ * Processing will be based on the state of the requested connection and
+ * the returned status.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance block
+ * msg pointer to the close response or confirmation message
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+spans_close_rsp(spp, msg)
+ struct spans *spp;
+ spans_msg *msg;
+{
+ struct spans_vccb *svp;
+
+ ATM_DEBUG2("spans_close_rsp: spp=0x%x, msg=0x%x\n", spp, msg);
+
+ /*
+ * Locate the VCCB for the connection
+ */
+ svp = spans_find_conn(spp, &msg->sm_close_rsp.clrsp_conn);
+ if (svp == NULL) {
+ return;
+ }
+
+ /*
+ * Check the VCCB state
+ */
+ if (svp->sv_sstate != SPANS_VC_CLOSE) {
+ return;
+ }
+
+ /*
+ * Cancel the retransmission timer
+ */
+ SPANS_VC_CANCEL((struct vccb *) svp);
+
+ /*
+ * Check the response from the remote end
+ */
+ switch (msg->sm_close_rsp.clrsp_result) {
+
+ case SPANS_OK:
+ /*
+ * Mark the VCCB as closed and notify the owner
+ */
+ svp->sv_sstate = SPANS_VC_FREE;
+ svp->sv_connvc->cvc_attr.cause.tag = T_ATM_PRESENT;
+ svp->sv_connvc->cvc_attr.cause.v.coding_standard =
+ T_ATM_ITU_CODING;
+ svp->sv_connvc->cvc_attr.cause.v.location =
+ T_ATM_LOC_USER;
+ svp->sv_connvc->cvc_attr.cause.v.cause_value =
+ T_ATM_CAUSE_NORMAL_CALL_CLEARING;
+ KM_ZERO(svp->sv_connvc->cvc_attr.cause.v.diagnostics,
+ sizeof(svp->sv_connvc->cvc_attr.cause.v.diagnostics));
+ atm_cm_cleared(svp->sv_connvc);
+ break;
+
+ case SPANS_NOVPVC:
+ case SPANS_BADDEST:
+ case SPANS_FAIL:
+ case SPANS_NORSC:
+ /*
+ * Mark the VCCB as closed and notify the owner
+ */
+ svp->sv_sstate = SPANS_VC_FREE;
+ svp->sv_connvc->cvc_attr.cause.tag = T_ATM_PRESENT;
+ svp->sv_connvc->cvc_attr.cause.v.coding_standard =
+ T_ATM_ITU_CODING;
+ svp->sv_connvc->cvc_attr.cause.v.location =
+ T_ATM_LOC_USER;
+ svp->sv_connvc->cvc_attr.cause.v.cause_value =
+ T_ATM_CAUSE_UNSPECIFIED_NORMAL;
+ KM_ZERO(svp->sv_connvc->cvc_attr.cause.v.diagnostics,
+ sizeof(svp->sv_connvc->cvc_attr.cause.v.diagnostics));
+ atm_cm_cleared(svp->sv_connvc);
+ break;
+
+ default:
+ log(LOG_ERR, "spans: unknown result %d in close rsp\n",
+ msg->sm_close_rsp.clrsp_result);
+ break;
+ }
+}
+
+
+/*
+ * Process a multi request or multi indication
+ *
+ * Called when a multi response or multi confirmation is received. We
+ * don't support multicast channels, so we just reject the request.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance block
+ * msg pointer to the multi request or indication message
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+spans_multi_req(spp, msg)
+ struct spans *spp;
+ spans_msg *msg;
+{
+ spans_msg *rsp_msg;
+
+ /*
+ * Get memory for a SPANS_MULTI_RSP message.
+ */
+ rsp_msg = (spans_msg *) atm_allocate(&spans_msgpool);
+ if (rsp_msg == NULL)
+ return;
+
+ /*
+ * Fill out the response.
+ */
+ rsp_msg->sm_vers = SPANS_VERS_1_0;
+ rsp_msg->sm_type = SPANS_MULTI_RSP;
+ rsp_msg->sm_multi_rsp.mursp_conn = msg->sm_multi_req.mureq_conn;
+ rsp_msg->sm_multi_rsp.mursp_result = SPANS_FAIL;
+ rsp_msg->sm_multi_rsp.mursp_rsrc = msg->sm_multi_req.mureq_desrsrc;
+ rsp_msg->sm_multi_rsp.mursp_vpvc = 0;
+
+ /*
+ * Send the response and free the message.
+ */
+ (void) spans_send_msg(spp, rsp_msg);
+ atm_free(rsp_msg);
+}
+
+
+/*
+ * Process an add request or add indication
+ *
+ * Called when an add response or add confirmation is received. We
+ * don't support multicast channels, so we just reject the request.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance block
+ * msg pointer to the add request or indication message
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+spans_add_req(spp, msg)
+ struct spans *spp;
+ spans_msg *msg;
+{
+ spans_msg *rsp_msg;
+
+ /*
+ * Get memory for a SPANS_ADD_RSP message.
+ */
+ rsp_msg = (spans_msg *) atm_allocate(&spans_msgpool);
+ if (rsp_msg == NULL)
+ return;
+
+ /*
+ * Fill out the response.
+ */
+ rsp_msg->sm_vers = SPANS_VERS_1_0;
+ rsp_msg->sm_type = SPANS_ADD_RSP;
+ rsp_msg->sm_add_rsp.adrsp_conn = msg->sm_add_req.adreq_desconn;
+ rsp_msg->sm_add_rsp.adrsp_result = SPANS_FAIL;
+ rsp_msg->sm_add_rsp.adrsp_rsrc.rsc_peak = 0;
+ rsp_msg->sm_add_rsp.adrsp_rsrc.rsc_mean = 0;
+ rsp_msg->sm_add_rsp.adrsp_rsrc.rsc_burst = 0;
+
+ /*
+ * Send the response and free the message.
+ */
+ (void) spans_send_msg(spp, rsp_msg);
+ atm_free(rsp_msg);
+}
+
+
+/*
+ * Process a join request
+ *
+ * Called when an join request is received. We don't support group
+ * addresses, so we just reject the request.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance block
+ * msg pointer to the join request message
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+spans_join_req(spp, msg)
+ struct spans *spp;
+ spans_msg *msg;
+{
+ spans_msg *rsp_msg;
+
+ /*
+ * Get memory for a SPANS_JOIN_CNF message.
+ */
+ rsp_msg = (spans_msg *) atm_allocate(&spans_msgpool);
+ if (rsp_msg == NULL)
+ return;
+
+ /*
+ * Fill out the response.
+ */
+ rsp_msg->sm_vers = SPANS_VERS_1_0;
+ rsp_msg->sm_type = SPANS_JOIN_CNF;
+ spans_addr_copy(&msg->sm_join_req.jnreq_addr,
+ &rsp_msg->sm_join_cnf.jncnf_addr);
+ rsp_msg->sm_join_cnf.jncnf_result = SPANS_FAIL;
+
+ /*
+ * Send the response and free the message.
+ */
+ (void) spans_send_msg(spp, rsp_msg);
+ atm_free(rsp_msg);
+}
+
+
+/*
+ * Process a leave request
+ *
+ * Called when an leave request is received. We don't support group
+ * addresses, so we just reject the request.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance block
+ * msg pointer to the leave request message
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+spans_leave_req(spp, msg)
+ struct spans *spp;
+ spans_msg *msg;
+{
+ spans_msg *rsp_msg;
+
+ /*
+ * Get memory for a SPANS_LEAVE_CNF message.
+ */
+ rsp_msg = (spans_msg *) atm_allocate(&spans_msgpool);
+ if (rsp_msg == NULL)
+ return;
+
+ /*
+ * Fill out the response.
+ */
+ rsp_msg->sm_vers = SPANS_VERS_1_0;
+ rsp_msg->sm_type = SPANS_LEAVE_CNF;
+ spans_addr_copy(&msg->sm_leave_req.lvreq_addr,
+ &rsp_msg->sm_leave_cnf.lvcnf_addr);
+ rsp_msg->sm_leave_cnf.lvcnf_result = SPANS_FAIL;
+
+ /*
+ * Send the response and free the message.
+ */
+ (void) spans_send_msg(spp, rsp_msg);
+ atm_free(rsp_msg);
+}
+
+
+/*
+ * Process a VCI range indication
+ *
+ * Called when a VCI range indication is received. Adjust the VCI
+ * bounds if they have changed.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance block
+ * msg pointer to the VCI range indication message
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+spans_vcir_ind(spp, msg)
+ struct spans *spp;
+ spans_msg *msg;
+{
+ /*
+ * Adjust the limits if they have changed
+ */
+ if (msg->sm_vcir_ind.vrind_min != spp->sp_min_vci) {
+ spp->sp_min_vci =
+ (msg->sm_vcir_ind.vrind_min <
+ SPANS_MIN_VCI ?
+ SPANS_MIN_VCI :
+ msg->sm_vcir_ind.vrind_min);
+ }
+ if (msg->sm_vcir_ind.vrind_max != spp->sp_max_vci) {
+ spp->sp_max_vci =
+ (msg->sm_vcir_ind.vrind_max >
+ SPANS_MAX_VCI ?
+ SPANS_MAX_VCI :
+ msg->sm_vcir_ind.vrind_max);
+ }
+}
+
+
+/*
+ * Process a query request
+ *
+ * Called when a query request is received. Respond with the
+ * appropriate query response.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance block
+ * msg pointer to the VCI range indication message
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+spans_query_req(spp, msg)
+ struct spans *spp;
+ spans_msg *msg;
+{
+ struct spans_vccb *svp = NULL;
+ spans_msg *rsp_msg;
+
+ ATM_DEBUG1("spans_query_req: msg=0x%x\n", msg);
+
+ /*
+ * Ignore an end-to-end query
+ */
+ if (msg->sm_query_req.qyreq_type == SPANS_QUERY_END_TO_END) {
+ return;
+ }
+
+ /*
+ * Get memory for a SPANS_QUERY_RSP message.
+ */
+ rsp_msg = (spans_msg *) atm_allocate(&spans_msgpool);
+ if (rsp_msg == NULL)
+ return;
+
+ /*
+ * Fill out the response.
+ */
+ rsp_msg->sm_vers = SPANS_VERS_1_0;
+ rsp_msg->sm_type = SPANS_QUERY_RSP;
+ rsp_msg->sm_query_rsp.qyrsp_conn = msg->sm_query_req.qyreq_conn;
+ rsp_msg->sm_query_rsp.qyrsp_type = msg->sm_query_req.qyreq_type;
+ rsp_msg->sm_query_rsp.qyrsp_data = 0;
+
+ /*
+ * Get the state of the requested connection
+ */
+ svp = spans_find_conn(spp, &msg->sm_query_req.qyreq_conn);
+ if (svp) {
+ switch(svp->sv_sstate) {
+ case SPANS_VC_NULL:
+ case SPANS_VC_FREE:
+ rsp_msg->sm_query_rsp.qyrsp_state =
+ SPANS_CONN_CLOSED;
+ break;
+ case SPANS_VC_OPEN:
+ rsp_msg->sm_query_rsp.qyrsp_state =
+ SPANS_CONN_OPEN;
+ break;
+ case SPANS_VC_POPEN:
+ case SPANS_VC_R_POPEN:
+ rsp_msg->sm_query_rsp.qyrsp_state =
+ SPANS_CONN_OPEN_PEND;
+ break;
+ case SPANS_VC_CLOSE:
+ case SPANS_VC_ABORT:
+ rsp_msg->sm_query_rsp.qyrsp_state =
+ SPANS_CONN_CLOSE_PEND;
+ break;
+ case SPANS_VC_ACTIVE:
+ case SPANS_VC_ACT_DOWN:
+ /*
+ * VCCB is for a PVC (shouldn't happen)
+ */
+ atm_free(rsp_msg);
+ return;
+ }
+ } else {
+ /*
+ * No VCCB found--connection doesn't exist
+ */
+ rsp_msg->sm_query_rsp.qyrsp_state = SPANS_CONN_CLOSED;
+ }
+
+ /*
+ * Send the response and free the message.
+ */
+ (void) spans_send_msg(spp, rsp_msg);
+ atm_free(rsp_msg);
+}
+
+
+/*
+ * Process a SPANS signalling message
+ *
+ * Called when a SPANS message is received. The message is converted
+ * into internal format with XDR and decoded by calling the appropriate
+ * mesage handling routine. Unrecognized and unexpected messages are
+ * logged.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance block
+ * m pointer to a buffer chain containing the SPANS message
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+spans_rcv_msg(spp, m)
+ struct spans *spp;
+ KBuffer *m;
+{
+ XDR xdrs;
+ spans_msg *msg;
+
+ /*
+ * Get storage for the message
+ */
+ msg = (spans_msg *)atm_allocate(&spans_msgpool);
+ if (msg == NULL) {
+ return;
+ }
+
+ /*
+ * Convert the message from network order to internal format
+ */
+ xdrmbuf_init(&xdrs, m, XDR_DECODE);
+ if (!xdr_spans_msg(&xdrs, msg)) {
+ log(LOG_ERR, "spans_rcv_msg: XDR decode failed\n");
+ spans_dump_buffer(m);
+ goto done;
+ }
+
+#ifdef NOTDEF
+ /*
+ * Debug--print some information about the message
+ */
+ if (msg->sm_type != SPANS_STAT_REQ &&
+ msg->sm_type != SPANS_STAT_IND &&
+ msg->sm_type != SPANS_STAT_RSP) {
+ printf("spans_rcv_msg: got ");
+ spans_print_msg(msg);
+ }
+#endif
+
+ /*
+ * Verify the message sm_vers
+ */
+ if (msg->sm_vers != SPANS_VERS_1_0) {
+ log(LOG_ERR, "spans: invalid message version 0x%x\n",
+ msg->sm_vers);
+ }
+
+ /*
+ * Ignore the message if SPANS isn't up yet
+ */
+ if (spp->sp_state != SPANS_ACTIVE &&
+ (spp->sp_state != SPANS_PROBE ||
+ (msg->sm_type != SPANS_STAT_REQ &&
+ msg->sm_type != SPANS_STAT_RSP &&
+ msg->sm_type != SPANS_STAT_IND))) {
+ goto done;
+ }
+
+ /*
+ * Process the message based on its type
+ */
+ switch(msg->sm_type) {
+ case SPANS_STAT_REQ:
+ spans_status_ind(spp, msg);
+ break;
+ case SPANS_STAT_IND:
+ spans_status_ind(spp, msg);
+ break;
+ case SPANS_STAT_RSP:
+ spans_status_rsp(spp, msg);
+ break;
+ case SPANS_OPEN_REQ:
+ spans_open_req(spp, msg);
+ break;
+ case SPANS_OPEN_IND:
+ spans_open_req(spp, msg);
+ break;
+ case SPANS_OPEN_RSP:
+ spans_open_rsp(spp, msg);
+ break;
+ case SPANS_OPEN_CNF:
+ spans_open_rsp(spp, msg);
+ break;
+ case SPANS_CLOSE_REQ:
+ spans_close_req(spp, msg);
+ break;
+ case SPANS_CLOSE_IND:
+ spans_close_req(spp, msg);
+ break;
+ case SPANS_CLOSE_RSP:
+ spans_close_rsp(spp, msg);
+ break;
+ case SPANS_CLOSE_CNF:
+ spans_close_rsp(spp, msg);
+ break;
+ case SPANS_RCLOSE_REQ:
+ spans_close_req(spp, msg);
+ break;
+ case SPANS_RCLOSE_IND:
+ spans_close_req(spp, msg);
+ break;
+ case SPANS_RCLOSE_RSP:
+ spans_close_rsp(spp, msg);
+ break;
+ case SPANS_RCLOSE_CNF:
+ spans_close_rsp(spp, msg);
+ break;
+ case SPANS_MULTI_REQ:
+ spans_multi_req(spp, msg);
+ break;
+ case SPANS_MULTI_IND:
+ spans_multi_req(spp, msg);
+ break;
+ case SPANS_MULTI_RSP:
+ log(LOG_ERR,
+ "spans: unexpected message (multi_rsp)\n");
+ break;
+ case SPANS_MULTI_CNF:
+ log(LOG_ERR,
+ "spans: unexpected message (multi_conf)\n");
+ break;
+ case SPANS_ADD_REQ:
+ spans_add_req(spp, msg);
+ break;
+ case SPANS_ADD_IND:
+ spans_add_req(spp, msg);
+ break;
+ case SPANS_ADD_RSP:
+ log(LOG_ERR,
+ "spans: unexpected message (add_rsp)\n");
+ break;
+ case SPANS_ADD_CNF:
+ log(LOG_ERR, "spans: unexpected message (add_conf)\n");
+ break;
+ case SPANS_JOIN_REQ:
+ spans_join_req(spp, msg);
+ break;
+ case SPANS_JOIN_CNF:
+ log(LOG_ERR, "spans: unexpected message (join_conf)\n");
+ break;
+ case SPANS_LEAVE_REQ:
+ spans_leave_req(spp, msg);
+ break;
+ case SPANS_LEAVE_CNF:
+ log(LOG_ERR,
+ "spans: unexpected message (leave_conf)\n");
+ break;
+ case SPANS_VCIR_IND:
+ spans_vcir_ind(spp, msg);
+ break;
+ case SPANS_QUERY_REQ:
+ spans_query_req(spp, msg);
+ break;
+ case SPANS_QUERY_RSP:
+ log(LOG_ERR,
+ "spans: unexpected message (query_rsp)\n");
+ break;
+ default:
+ log(LOG_ERR, "spans: unknown SPANS message type %d\n",
+ msg->sm_type);
+ }
+
+done:
+ /*
+ * Free the incoming message (both buffer and internal format) if
+ * necessary.
+ */
+ if (msg)
+ atm_free(msg);
+ if (m)
+ KB_FREEALL(m);
+}
diff --git a/sys/netatm/spans/spans_print.c b/sys/netatm/spans/spans_print.c
new file mode 100644
index 0000000..60dc670
--- /dev/null
+++ b/sys/netatm/spans/spans_print.c
@@ -0,0 +1,1062 @@
+/*
+ *
+ * ===================================
+ * 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: spans_print.c,v 1.4 1997/05/06 22:17:11 mks Exp $
+ *
+ */
+
+/*
+ * SPANS Signalling Manager
+ * ---------------------------
+ *
+ * SPANS Print Routines.
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: spans_print.c,v 1.4 1997/05/06 22:17:11 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include "spans_xdr.h"
+#include <netatm/spans/spans_var.h>
+
+/*
+ * If LONGPRINT is defined, every field of the SPANS message will be
+ * printed. If not, a shorter summary (useful for debugging without
+ * swamping the console) is printed.
+ */
+/* #define LONGPRINT */
+
+/*
+ * Local functions
+ */
+static void inc_indent __P((void));
+static void dec_indent __P((void));
+static void spans_aal_str __P((spans_aal *, char *));
+static void spans_result_str __P((spans_result *, char *));
+static void spans_msgtype_str __P((spans_msgtype *, char *));
+static void spans_query_type_str __P((spans_query_type *, char *));
+static void spans_state_str __P((spans_query_type *, char *));
+static void spans_print_version __P((spans_version *));
+static void spans_print_vpvc __P((spans_vpvc *));
+static void spans_print_vpvc_pref __P((spans_vpvc_pref *));
+static void spans_print_addr __P((spans_addr *));
+static void spans_print_sap __P((spans_sap *));
+static void spans_print_atm_conn __P((spans_atm_conn *));
+static void spans_print_resrc __P((spans_resrc *));
+static void spans_print_aal __P((spans_aal *));
+static void spans_print_result __P((spans_result *));
+static void spans_print_msgtype __P((spans_msgtype *));
+static void spans_print_parm_stat_req __P((spans_parm_stat_req *));
+static void spans_print_parm_stat_ind __P((spans_parm_stat_ind *));
+static void spans_print_parm_stat_rsp __P((spans_parm_stat_rsp *));
+static void spans_print_parm_open_req __P((spans_parm_open_req *));
+static void spans_print_parm_open_ind __P((spans_parm_open_ind *));
+static void spans_print_parm_open_rsp __P((spans_parm_open_rsp *));
+static void spans_print_parm_open_cnf __P((spans_parm_open_cnf *));
+static void spans_print_parm_close_req __P((spans_parm_close_req *));
+static void spans_print_parm_close_ind __P((spans_parm_close_ind *));
+static void spans_print_parm_close_rsp __P((spans_parm_close_rsp *));
+static void spans_print_parm_close_cnf __P((spans_parm_close_cnf *));
+static void spans_print_parm_rclose_req __P((spans_parm_rclose_req *));
+static void spans_print_parm_rclose_ind __P((spans_parm_rclose_ind *));
+static void spans_print_parm_rclose_rsp __P((spans_parm_rclose_rsp *));
+static void spans_print_parm_rclose_cnf __P((spans_parm_rclose_cnf *));
+static void spans_print_parm_multi_req __P((spans_parm_multi_req *));
+static void spans_print_parm_multi_ind __P((spans_parm_multi_ind *));
+static void spans_print_parm_multi_rsp __P((spans_parm_multi_rsp *));
+static void spans_print_parm_multi_cnf __P((spans_parm_multi_cnf *));
+static void spans_print_parm_add_req __P((spans_parm_add_req *));
+static void spans_print_parm_add_ind __P((spans_parm_add_ind *));
+static void spans_print_parm_add_rsp __P((spans_parm_add_rsp *));
+static void spans_print_parm_add_cnf __P((spans_parm_add_cnf *));
+static void spans_print_parm_join_req __P((spans_parm_join_req *));
+static void spans_print_parm_join_cnf __P((spans_parm_join_cnf *));
+static void spans_print_parm_leave_req __P((spans_parm_leave_req *));
+static void spans_print_parm_leave_cnf __P((spans_parm_leave_cnf *));
+static void spans_print_parm_vcir_ind __P((spans_parm_vcir_ind *));
+static void spans_print_parm_query_req __P((spans_parm_query_req *));
+static void spans_print_parm_query_rsp __P((spans_parm_query_rsp *));
+static void spans_print_msgbody __P((spans_msgbody *));
+
+
+/*
+ * Local variables
+ */
+#define MAX_INDENT 10
+#define INIT_INDENT &indent_str[MAX_INDENT]
+static char *spans_indent;
+static char indent_str[11] = " ";
+
+static void
+inc_indent()
+{
+ if (spans_indent != &indent_str[0]) {
+ *spans_indent--;
+ }
+}
+
+static void
+dec_indent()
+{
+ if (spans_indent != INIT_INDENT) {
+ *spans_indent++;
+ }
+}
+
+static void
+spans_aal_str(objp, dest)
+ spans_aal *objp;
+ char *dest;
+{
+ static char *aal_names[] = {
+ "SPANS_AAL0",
+ "SPANS_AAL1",
+ "SPANS_AAL2",
+ "SPANS_AAL3",
+ "SPANS_AAL4",
+ "SPANS_AAL5"
+ };
+
+ if (*objp < SPANS_AAL0 || *objp > SPANS_AAL5) {
+ sprintf(dest, "Invalid (%d)", (int)*objp);
+ } else {
+ sprintf(dest, "%s (%d)", aal_names[(int)*objp],
+ (int)*objp);
+ }
+}
+
+static void
+spans_result_str(objp, dest)
+ spans_result *objp;
+ char *dest;
+{
+ static char *result_names[] = {
+ "SPANS_OK",
+ "SPANS_FAIL",
+ "SPANS_NOVPVC",
+ "SPANS_NORSC",
+ "SPANS_BADDEST"
+ };
+
+ if (*objp < SPANS_OK || *objp > SPANS_BADDEST) {
+ sprintf(dest, "Invalid (%d)", (int)*objp);
+ } else {
+ sprintf(dest, "%s (%d)",
+ result_names[(int)*objp], (int)*objp);
+ }
+}
+
+static void
+spans_msgtype_str(objp, dest)
+ spans_msgtype *objp;
+ char *dest;
+{
+ int i;
+
+ static struct {
+ spans_msgtype type;
+ char *name;
+ } msgtype_names[] = {
+ { SPANS_STAT_REQ, "SPANS_STAT_REQ" },
+ { SPANS_STAT_IND, "SPANS_STAT_IND" },
+ { SPANS_STAT_RSP, "SPANS_STAT_RSP" },
+ { SPANS_OPEN_REQ, "SPANS_OPEN_REQ" },
+ { SPANS_OPEN_IND, "SPANS_OPEN_IND" },
+ { SPANS_OPEN_RSP, "SPANS_OPEN_RSP" },
+ { SPANS_OPEN_CNF, "SPANS_OPEN_CNF" },
+ { SPANS_CLOSE_REQ, "SPANS_CLOSE_REQ" },
+ { SPANS_CLOSE_IND, "SPANS_CLOSE_IND" },
+ { SPANS_CLOSE_RSP, "SPANS_CLOSE_RSP" },
+ { SPANS_CLOSE_CNF, "SPANS_CLOSE_CNF" },
+ { SPANS_RCLOSE_REQ, "SPANS_RCLOSE_REQ" },
+ { SPANS_RCLOSE_IND, "SPANS_RCLOSE_IND" },
+ { SPANS_RCLOSE_RSP, "SPANS_RCLOSE_RSP" },
+ { SPANS_RCLOSE_CNF, "SPANS_RCLOSE_CNF" },
+ { SPANS_MULTI_REQ, "SPANS_MULTI_REQ" },
+ { SPANS_MULTI_IND, "SPANS_MULTI_IND" },
+ { SPANS_MULTI_RSP, "SPANS_MULTI_RSP" },
+ { SPANS_MULTI_CNF, "SPANS_MULTI_CNF" },
+ { SPANS_ADD_REQ, "SPANS_ADD_REQ" },
+ { SPANS_ADD_IND, "SPANS_ADD_IND" },
+ { SPANS_ADD_RSP, "SPANS_ADD_RSP" },
+ { SPANS_ADD_CNF, "SPANS_ADD_CNF" },
+ { SPANS_JOIN_REQ, "SPANS_JOIN_REQ" },
+ { SPANS_JOIN_CNF, "SPANS_JOIN_CNF" },
+ { SPANS_LEAVE_REQ, "SPANS_LEAVE_REQ" },
+ { SPANS_LEAVE_CNF, "SPANS_LEAVE_CNF" },
+ { SPANS_VCIR_IND, "SPANS_VCIR_IND" },
+ { SPANS_QUERY_REQ, "SPANS_QUERY_REQ" },
+ { SPANS_QUERY_RSP, "SPANS_QUERY_RSP" },
+ { 0, (char *) 0 }
+ };
+
+ /*
+ * Search the name table for the specified type
+ */
+ for (i=0; msgtype_names[i].name; i++) {
+ if (*objp == msgtype_names[i].type) {
+ sprintf(dest, "%s (%d)",
+ msgtype_names[i].name,
+ (int)*objp);
+ return;
+ }
+ }
+
+ /*
+ * Type was not found--return an error indicator
+ */
+ sprintf(dest, "Invalid (%d)", (int)*objp);
+}
+
+static void
+spans_query_type_str(objp, dest)
+ spans_query_type *objp;
+ char *dest;
+{
+ static char *query_names[] = {
+ "SPANS_QUERY_NORMAL",
+ "SPANS_QUERY_DEBUG",
+ "SPANS_QUERY_END_TO_END"
+ };
+
+ if (*objp < SPANS_QUERY_NORMAL ||
+ *objp > SPANS_QUERY_END_TO_END) {
+ sprintf(dest, "Invalid (%d)", (int)*objp);
+ } else {
+ sprintf(dest, "%s (%d)", query_names[(int)*objp],
+ (int)*objp);
+ }
+}
+
+static void
+spans_state_str(objp, dest)
+ spans_query_type *objp;
+ char *dest;
+{
+ static char *state_names[] = {
+ "SPANS_CONN_OPEN",
+ "SPANS_CONN_OPEN_PEND",
+ "SPANS_CONN_CLOSE_PEND",
+ "SPANS_CONN_CLOSED"
+ };
+
+ if (*objp < SPANS_CONN_OPEN || *objp > SPANS_CONN_CLOSED) {
+ sprintf(dest, "Invalid (%d)", (int)*objp);
+ } else {
+ sprintf(dest, "%s (%d)", state_names[(int)*objp],
+ (int)*objp);
+ }
+}
+
+#ifdef LONGPRINT
+
+static void
+spans_print_version(objp)
+ spans_version *objp;
+{
+ printf("%sspans_version 0x%x\n", spans_indent, *objp);
+}
+
+static void
+spans_print_vpvc(objp)
+ spans_vpvc *objp;
+{
+ printf("%sVP/VC %d/%d\n", spans_indent,
+ SPANS_EXTRACT_VPI(*objp),
+ SPANS_EXTRACT_VCI(*objp));
+}
+
+static void
+spans_print_vpvc_pref(objp)
+ spans_vpvc_pref *objp;
+{
+ printf("%sspans_vpvc_pref\n", spans_indent);
+ inc_indent();
+ printf("%s%s\n", spans_indent,
+ (objp->vpf_valid ? "Valid" : "Not valid"));
+ spans_print_vpvc(&objp->vpf_vpvc);
+ dec_indent();
+}
+
+static void
+spans_print_addr(objp)
+ spans_addr *objp;
+{
+ char addr_str[80];
+
+ strncpy(addr_str, spans_addr_print(objp), sizeof(addr_str));
+ printf("%sspans_addr %s\n", spans_indent, addr_str);
+}
+
+static void
+spans_print_sap(objp)
+ spans_sap *objp;
+{
+ printf("%sSAP %d\n", spans_indent, *objp);
+}
+
+static void
+spans_print_atm_conn(objp)
+ spans_atm_conn *objp;
+{
+ printf("%sspans_atm_conn\n", spans_indent);
+ inc_indent();
+ spans_print_addr(&objp->con_dst);
+ spans_print_addr(&objp->con_src);
+ spans_print_sap(&objp->con_dsap);
+ spans_print_sap(&objp->con_ssap);
+ dec_indent();
+}
+
+static void
+spans_print_resrc(objp)
+ spans_resrc *objp;
+{
+ printf("%sspans_resrc\n", spans_indent);
+ inc_indent();
+ printf("%srsc_peak %d\n", spans_indent, objp->rsc_peak);
+ printf("%srsc_mean %d\n", spans_indent, objp->rsc_mean);
+ printf("%srsc_burst %d\n", spans_indent, objp->rsc_burst);
+ dec_indent();
+}
+
+static void
+spans_print_aal(objp)
+ spans_aal *objp;
+{
+ char aal_str[80];
+
+ spans_aal_str(objp, aal_str);
+ printf("%sspans_aal %s\n", spans_indent, aal_str);
+}
+
+static void
+spans_print_result(objp)
+ spans_result *objp;
+{
+ char result_str[80];
+
+ spans_result_str(objp, result_str);
+ printf("%sspans_result %s\n", spans_indent, result_str);
+}
+
+static void
+spans_print_msgtype(objp)
+ spans_msgtype *objp;
+{
+ char msgtype_str[80];
+
+ spans_msgtype_str(objp, msgtype_str);
+ printf("%sspans_msgtype %s\n", spans_indent, msgtype_str);
+}
+
+static void
+spans_print_parm_stat_req(objp)
+ spans_parm_stat_req *objp;
+{
+ printf("%sspans_parm_stat_req\n", spans_indent);
+ inc_indent();
+ printf("%sstreq_es_epoch %d\n", spans_indent,
+ objp->streq_es_epoch);
+ dec_indent();
+}
+
+static void
+spans_print_parm_stat_ind(objp)
+ spans_parm_stat_ind *objp;
+{
+ printf("%sspans_parm_stat_ind\n", spans_indent);
+ inc_indent();
+ printf("%sstind_sw_epoch %d\n", spans_indent,
+ objp->stind_sw_epoch);
+ spans_print_addr(&objp->stind_es_addr);
+ spans_print_addr(&objp->stind_sw_addr);
+ dec_indent();
+}
+
+static void
+spans_print_parm_stat_rsp(objp)
+ spans_parm_stat_rsp *objp;
+{
+ printf("%sspans_parm_stat_rsp\n", spans_indent);
+ inc_indent();
+ printf("%sstrsp_es_epoch %d\n", spans_indent,
+ objp->strsp_es_epoch);
+ spans_print_addr(&objp->strsp_es_addr);
+ dec_indent();
+}
+
+static void
+spans_print_parm_open_req(objp)
+ spans_parm_open_req *objp;
+{
+ printf("%sspans_parm_open_req\n", spans_indent);
+ inc_indent();
+ spans_print_atm_conn(&objp->opreq_conn);
+ spans_print_aal(&objp->opreq_aal);
+ spans_print_resrc(&objp->opreq_desrsrc);
+ spans_print_resrc(&objp->opreq_minrsrc);
+ spans_print_vpvc_pref(&objp->opreq_vpvc);
+ dec_indent();
+}
+
+static void
+spans_print_parm_open_ind(objp)
+ spans_parm_open_ind *objp;
+{
+ printf("%sspans_parm_open_ind\n", spans_indent);
+ inc_indent();
+ spans_print_atm_conn(&objp->opind_conn);
+ spans_print_aal(&objp->opind_aal);
+ spans_print_resrc(&objp->opind_desrsrc);
+ spans_print_resrc(&objp->opind_minrsrc);
+ spans_print_vpvc_pref(&objp->opind_vpvc);
+ dec_indent();
+}
+
+static void
+spans_print_parm_open_rsp(objp)
+ spans_parm_open_rsp *objp;
+{
+ printf("%sspans_parm_open_rsp\n", spans_indent);
+ inc_indent();
+ spans_print_atm_conn(&objp->oprsp_conn);
+ spans_print_result(&objp->oprsp_result);
+ spans_print_resrc(&objp->oprsp_rsrc);
+ spans_print_vpvc(&objp->oprsp_vpvc);
+ dec_indent();
+}
+
+static void
+spans_print_parm_open_cnf(objp)
+ spans_parm_open_cnf *objp;
+{
+ printf("%sspans_parm_open_cnf\n", spans_indent);
+ inc_indent();
+ spans_print_atm_conn(&objp->opcnf_conn);
+ spans_print_result(&objp->opcnf_result);
+ spans_print_resrc(&objp->opcnf_rsrc);
+ spans_print_vpvc(&objp->opcnf_vpvc);
+ dec_indent();
+}
+
+static void
+spans_print_parm_close_req(objp)
+ spans_parm_close_req *objp;
+{
+ printf("%sspans_parm_close_req\n", spans_indent);
+ inc_indent();
+ spans_print_atm_conn(&objp->clreq_conn);
+ dec_indent();
+}
+
+static void
+spans_print_parm_close_ind(objp)
+ spans_parm_close_ind *objp;
+{
+ printf("%sspans_parm_close_ind\n", spans_indent);
+ inc_indent();
+ spans_print_atm_conn(&objp->clind_conn);
+ dec_indent();
+}
+
+static void
+spans_print_parm_close_rsp(objp)
+ spans_parm_close_rsp *objp;
+{
+ printf("%sspans_parm_close_rsp\n", spans_indent);
+ inc_indent();
+ spans_print_atm_conn(&objp->clrsp_conn);
+ spans_print_result(&objp->clrsp_result);
+ dec_indent();
+}
+
+static void
+spans_print_parm_close_cnf(objp)
+ spans_parm_close_cnf *objp;
+{
+ printf("%sspans_parm_close_cnf\n", spans_indent);
+ inc_indent();
+ spans_print_atm_conn(&objp->clcnf_conn);
+ spans_print_result(&objp->clcnf_result);
+ dec_indent();
+}
+
+static void
+spans_print_parm_rclose_req(objp)
+ spans_parm_rclose_req *objp;
+{
+ printf("%sspans_parm_rclose_req\n", spans_indent);
+ inc_indent();
+ spans_print_atm_conn(&objp->rcreq_conn);
+ dec_indent();
+}
+
+static void
+spans_print_parm_rclose_ind(objp)
+ spans_parm_rclose_ind *objp;
+{
+ printf("%sspans_parm_rclose_ind\n", spans_indent);
+ inc_indent();
+ spans_print_atm_conn(&objp->rcind_conn);
+ dec_indent();
+}
+
+static void
+spans_print_parm_rclose_rsp(objp)
+ spans_parm_rclose_rsp *objp;
+{
+ printf("%sspans_parm_rclose_rsp\n", spans_indent);
+ inc_indent();
+ spans_print_atm_conn(&objp->rcrsp_conn);
+ spans_print_result(&objp->rcrsp_result);
+ dec_indent();
+}
+
+static void
+spans_print_parm_rclose_cnf(objp)
+ spans_parm_rclose_cnf *objp;
+{
+ printf("%sspans_parm_rclose_cnf\n", spans_indent);
+ inc_indent();
+ spans_print_atm_conn(&objp->rccnf_conn);
+ spans_print_result(&objp->rccnf_result);
+ dec_indent();
+}
+
+static void
+spans_print_parm_multi_req(objp)
+ spans_parm_multi_req *objp;
+{
+ printf("%sspans_parm_multi_req\n", spans_indent);
+ inc_indent();
+ spans_print_atm_conn(&objp->mureq_conn);
+ spans_print_aal(&objp->mureq_aal);
+ spans_print_resrc(&objp->mureq_desrsrc);
+ spans_print_resrc(&objp->mureq_minrsrc);
+ spans_print_vpvc(&objp->mureq_vpvc);
+ dec_indent();
+}
+
+static void
+spans_print_parm_multi_ind(objp)
+ spans_parm_multi_ind *objp;
+{
+ printf("%sspans_parm_multi_ind\n", spans_indent);
+ inc_indent();
+ spans_print_atm_conn(&objp->muind_conn);
+ spans_print_aal(&objp->muind_aal);
+ spans_print_resrc(&objp->muind_desrsrc);
+ spans_print_resrc(&objp->muind_minrsrc);
+ spans_print_vpvc(&objp->muind_vpvc);
+ dec_indent();
+}
+
+static void
+spans_print_parm_multi_rsp(objp)
+ spans_parm_multi_rsp *objp;
+{
+ printf("%sspans_parm_multi_rsp\n", spans_indent);
+ inc_indent();
+ spans_print_atm_conn(&objp->mursp_conn);
+ spans_print_result(&objp->mursp_result);
+ spans_print_resrc(&objp->mursp_rsrc);
+ spans_print_vpvc(&objp->mursp_vpvc);
+ dec_indent();
+}
+
+static void
+spans_print_parm_multi_cnf(objp)
+ spans_parm_multi_cnf *objp;
+{
+ printf("%sspans_parm_multi_cnf\n", spans_indent);
+ inc_indent();
+ spans_print_atm_conn(&objp->mucnf_conn);
+ spans_print_result(&objp->mucnf_result);
+ spans_print_resrc(&objp->mucnf_rsrc);
+ spans_print_vpvc(&objp->mucnf_vpvc);
+ dec_indent();
+}
+
+static void
+spans_print_parm_add_req(objp)
+ spans_parm_add_req *objp;
+{
+ printf("%sspans_parm_add_req\n", spans_indent);
+ inc_indent();
+ spans_print_atm_conn(&objp->adreq_desconn);
+ spans_print_atm_conn(&objp->adreq_xstconn);
+ dec_indent();
+}
+
+static void
+spans_print_parm_add_ind(objp)
+ spans_parm_add_ind *objp;
+{
+ printf("%sspans_parm_add_ind\n", spans_indent);
+ inc_indent();
+ spans_print_atm_conn(&objp->adind_desconn);
+ spans_print_atm_conn(&objp->adind_xstconn);
+ dec_indent();
+}
+
+static void
+spans_print_parm_add_rsp(objp)
+ spans_parm_add_rsp *objp;
+{
+ printf("%sspans_parm_add_rsp\n", spans_indent);
+ inc_indent();
+ spans_print_atm_conn(&objp->adrsp_conn);
+ spans_print_result(&objp->adrsp_result);
+ spans_print_resrc(&objp->adrsp_rsrc);
+ dec_indent();
+}
+
+static void
+spans_print_parm_add_cnf(objp)
+ spans_parm_add_cnf *objp;
+{
+ printf("%sspans_parm_add_cnf\n", spans_indent);
+ inc_indent();
+ spans_print_atm_conn(&objp->adcnf_conn);
+ spans_print_result(&objp->adcnf_result);
+ spans_print_resrc(&objp->adcnf_rsrc);
+ dec_indent();
+}
+
+static void
+spans_print_parm_join_req(objp)
+ spans_parm_join_req *objp;
+{
+ printf("%sspans_parm_join_req\n", spans_indent);
+ inc_indent();
+ spans_print_addr(&objp->jnreq_addr);
+ dec_indent();
+}
+
+static void
+spans_print_parm_join_cnf(objp)
+ spans_parm_join_cnf *objp;
+{
+ printf("%sspans_print_parm_join_cnf\n", spans_indent);
+ inc_indent();
+ spans_print_addr(&objp->jncnf_addr);
+ spans_print_result(&objp->jncnf_result);
+ dec_indent();
+}
+
+static void
+spans_print_parm_leave_req(objp)
+ spans_parm_leave_req *objp;
+{
+ printf("%sspans_print_parm_leave_req\n", spans_indent);
+ inc_indent();
+ spans_print_addr(&objp->lvreq_addr);
+ dec_indent();
+}
+
+static void
+spans_print_parm_leave_cnf(objp)
+ spans_parm_leave_cnf *objp;
+{
+ printf("%sspans_parm_leave_cnf\n", spans_indent);
+ inc_indent();
+ spans_print_addr(&objp->lvcnf_addr);
+ spans_print_result(&objp->lvcnf_result);
+ dec_indent();
+}
+
+static void
+spans_print_parm_vcir_ind(objp)
+ spans_parm_vcir_ind *objp;
+{
+ printf("%sspans_parm_vcir_ind\n", spans_indent);
+ inc_indent();
+ printf("%svrind_min %d\n", spans_indent, objp->vrind_min);
+ printf("%svrind_max %d\n", spans_indent, objp->vrind_max);
+ dec_indent();
+}
+
+static void
+spans_print_parm_query_req(objp)
+ spans_parm_query_req *objp;
+{
+ char query_type_str[80];
+
+ printf("%sspans_parm_query_req\n", spans_indent);
+ inc_indent();
+ spans_print_atm_conn(&objp->qyreq_conn);
+ spans_query_type_str(&objp->qyreq_type, query_type_str);
+ printf("%sqyreq_type %s\n", spans_indent, query_type_str);
+ dec_indent();
+}
+
+static void
+spans_print_parm_query_rsp(objp)
+ spans_parm_query_rsp *objp;
+{
+ char query_type_str[80], state_type_str[80];
+
+ printf("%sspans_parm_query_rsp\n", spans_indent);
+ inc_indent();
+ spans_print_atm_conn(&objp->qyrsp_conn);
+ spans_query_type_str(&objp->qyrsp_type, query_type_str);
+ printf("%sqyrsp_type %s\n", spans_indent, query_type_str);
+ spans_state_str(&objp->qyrsp_state, state_type_str);
+ printf("%sqyrsp_state %s\n", spans_indent, state_type_str);
+ printf("%sqyrsp_data 0x%x\n", spans_indent,
+ objp->qyrsp_data);
+ dec_indent();
+}
+
+static void
+spans_print_msgbody(objp)
+ spans_msgbody *objp;
+{
+ printf("%sspans_msgbody\n", spans_indent);
+ inc_indent();
+ spans_print_msgtype(&objp->mb_type);
+ switch (objp->mb_type) {
+ case SPANS_STAT_REQ:
+ spans_print_parm_stat_req(&objp->spans_msgbody_u.mb_stat_req);
+ break;
+ case SPANS_STAT_IND:
+ spans_print_parm_stat_ind(&objp->spans_msgbody_u.mb_stat_ind);
+ break;
+ case SPANS_STAT_RSP:
+ spans_print_parm_stat_rsp(&objp->spans_msgbody_u.mb_stat_rsp);
+ break;
+ case SPANS_OPEN_REQ:
+ spans_print_parm_open_req(&objp->spans_msgbody_u.mb_open_req);
+ break;
+ case SPANS_OPEN_IND:
+ spans_print_parm_open_ind(&objp->spans_msgbody_u.mb_open_ind);
+ break;
+ case SPANS_OPEN_RSP:
+ spans_print_parm_open_rsp(&objp->spans_msgbody_u.mb_open_rsp);
+ break;
+ case SPANS_OPEN_CNF:
+ spans_print_parm_open_cnf(&objp->spans_msgbody_u.mb_open_cnf);
+ break;
+ case SPANS_CLOSE_REQ:
+ spans_print_parm_close_req(&objp->spans_msgbody_u.mb_close_req);
+ break;
+ case SPANS_CLOSE_IND:
+ spans_print_parm_close_ind(&objp->spans_msgbody_u.mb_close_ind);
+ break;
+ case SPANS_CLOSE_RSP:
+ spans_print_parm_close_rsp(&objp->spans_msgbody_u.mb_close_rsp);
+ break;
+ case SPANS_CLOSE_CNF:
+ spans_print_parm_close_cnf(&objp->spans_msgbody_u.mb_close_cnf);
+ break;
+ case SPANS_RCLOSE_REQ:
+ spans_print_parm_rclose_req(&objp->spans_msgbody_u.mb_rclose_req);
+ break;
+ case SPANS_RCLOSE_IND:
+ spans_print_parm_rclose_ind(&objp->spans_msgbody_u.mb_rclose_ind);
+ break;
+ case SPANS_RCLOSE_RSP:
+ spans_print_parm_rclose_rsp(&objp->spans_msgbody_u.mb_rclose_rsp);
+ break;
+ case SPANS_RCLOSE_CNF:
+ spans_print_parm_rclose_cnf(&objp->spans_msgbody_u.mb_rclose_cnf);
+ break;
+ case SPANS_MULTI_REQ:
+ spans_print_parm_multi_req(&objp->spans_msgbody_u.mb_multi_req);
+ break;
+ case SPANS_MULTI_IND:
+ spans_print_parm_multi_ind(&objp->spans_msgbody_u.mb_multi_ind);
+ break;
+ case SPANS_MULTI_RSP:
+ spans_print_parm_multi_rsp(&objp->spans_msgbody_u.mb_multi_rsp);
+ break;
+ case SPANS_MULTI_CNF:
+ spans_print_parm_multi_cnf(&objp->spans_msgbody_u.mb_multi_cnf);
+ break;
+ case SPANS_ADD_REQ:
+ spans_print_parm_add_req(&objp->spans_msgbody_u.mb_add_req);
+ break;
+ case SPANS_ADD_IND:
+ spans_print_parm_add_ind(&objp->spans_msgbody_u.mb_add_ind);
+ break;
+ case SPANS_ADD_RSP:
+ spans_print_parm_add_rsp(&objp->spans_msgbody_u.mb_add_rsp);
+ break;
+ case SPANS_ADD_CNF:
+ spans_print_parm_add_cnf(&objp->spans_msgbody_u.mb_add_cnf);
+ break;
+ case SPANS_JOIN_REQ:
+ spans_print_parm_join_req(&objp->spans_msgbody_u.mb_join_req);
+ break;
+ case SPANS_JOIN_CNF:
+ spans_print_parm_join_cnf(&objp->spans_msgbody_u.mb_join_cnf);
+ break;
+ case SPANS_LEAVE_REQ:
+ spans_print_parm_leave_req(&objp->spans_msgbody_u.mb_leave_req);
+ break;
+ case SPANS_LEAVE_CNF:
+ spans_print_parm_leave_cnf(&objp->spans_msgbody_u.mb_leave_cnf);
+ break;
+ case SPANS_VCIR_IND:
+ spans_print_parm_vcir_ind(&objp->spans_msgbody_u.mb_vcir_ind);
+ break;
+ case SPANS_QUERY_REQ:
+ spans_print_parm_query_req(&objp->spans_msgbody_u.mb_query_req);
+ break;
+ case SPANS_QUERY_RSP:
+ spans_print_parm_query_rsp(&objp->spans_msgbody_u.mb_query_rsp);
+ break;
+ }
+ dec_indent();
+}
+
+void
+spans_print_msg(objp)
+ spans_msg *objp;
+{
+ spans_indent = INIT_INDENT;
+ printf("%sspans_msg\n", spans_indent);
+ inc_indent();
+ spans_print_version(&objp->sm_vers);
+ spans_print_msgbody(&objp->sm_body);
+ dec_indent();
+}
+
+#else /* ifdef LONGPRINT */
+
+static void
+spans_print_msgbody(objp)
+ spans_msgbody *objp;
+{
+ char daddr[80], msgtype_str[80], result_str[80], saddr[80];
+ spans_parm_stat_req *streq_p;
+ spans_parm_stat_ind *stind_p;
+ spans_parm_stat_rsp *strsp_p;
+ spans_parm_open_req *opreq_p;
+ spans_parm_open_ind *opind_p;
+ spans_parm_open_rsp *oprsp_p;
+ spans_parm_open_cnf *opcnf_p;
+ spans_parm_close_req *clreq_p;
+ spans_parm_close_ind *clind_p;
+ spans_parm_close_rsp *clrsp_p;
+ spans_parm_close_cnf *clcnf_p;
+ spans_parm_rclose_req *rcreq_p;
+ spans_parm_rclose_ind *rcind_p;
+ spans_parm_rclose_rsp *rcrsp_p;
+ spans_parm_rclose_cnf *rccnf_p;
+
+ spans_msgtype_str(&objp->mb_type, msgtype_str);
+ printf("%s: ", msgtype_str);
+ switch (objp->mb_type) {
+ case SPANS_STAT_REQ:
+ streq_p = &objp->spans_msgbody_u.mb_stat_req;
+ printf("es_epoch=0x%x", streq_p->streq_es_epoch);
+ break;
+ case SPANS_STAT_IND:
+ stind_p = &objp->spans_msgbody_u.mb_stat_ind;
+ strncpy(daddr, spans_addr_print(&stind_p->stind_es_addr),
+ sizeof(daddr));
+ strncpy(saddr, spans_addr_print(&stind_p->stind_sw_addr),
+ sizeof(daddr));
+ printf("sw_epoch=0x%x, es_addr=%s, sw_addr=0x%s",
+ stind_p->stind_sw_epoch,
+ daddr, saddr);
+ break;
+ case SPANS_STAT_RSP:
+ strsp_p = &objp->spans_msgbody_u.mb_stat_rsp;
+ strncpy(daddr, spans_addr_print(&strsp_p->strsp_es_addr),
+ sizeof(daddr));
+ printf("es_epoch=0x%x, es_addr=%s",
+ strsp_p->strsp_es_epoch, daddr);
+ break;
+ case SPANS_OPEN_REQ:
+ opreq_p = &objp->spans_msgbody_u.mb_open_req;
+ strncpy(daddr, spans_addr_print(&opreq_p->opreq_conn.con_dst),
+ sizeof(daddr));
+ strncpy(saddr, spans_addr_print(&opreq_p->opreq_conn.con_src),
+ sizeof(saddr));
+ printf("daddr=%s, saddr=%s, dsap=%d, ssap=%d, aal=%d",
+ daddr, saddr,
+ opreq_p->opreq_conn.con_dsap,
+ opreq_p->opreq_conn.con_ssap,
+ opreq_p->opreq_aal);
+ if (opreq_p->opreq_vpvc.vpf_valid)
+ printf(", vp.vc=%d.%d",
+ SPANS_EXTRACT_VPI(opreq_p->opreq_vpvc.vpf_vpvc),
+ SPANS_EXTRACT_VCI(opreq_p->opreq_vpvc.vpf_vpvc));
+ break;
+ case SPANS_OPEN_IND:
+ opind_p = &objp->spans_msgbody_u.mb_open_ind;
+ strncpy(daddr, spans_addr_print(&opind_p->opind_conn.con_dst),
+ sizeof(daddr));
+ strncpy(saddr, spans_addr_print(&opind_p->opind_conn.con_src),
+ sizeof(saddr));
+ printf("daddr=%s, saddr=%s, dsap=%d, ssap=%d, aal=%d",
+ daddr, saddr,
+ opind_p->opind_conn.con_dsap,
+ opind_p->opind_conn.con_ssap,
+ opind_p->opind_aal);
+ if (opind_p->opind_vpvc.vpf_valid)
+ printf(", vp.vc=%d.%d",
+ SPANS_EXTRACT_VPI(opind_p->opind_vpvc.vpf_vpvc),
+ SPANS_EXTRACT_VCI(opind_p->opind_vpvc.vpf_vpvc));
+ break;
+ case SPANS_OPEN_RSP:
+ oprsp_p = &objp->spans_msgbody_u.mb_open_rsp;
+ strncpy(daddr, spans_addr_print(&oprsp_p->oprsp_conn.con_dst),
+ sizeof(daddr));
+ strncpy(saddr, spans_addr_print(&oprsp_p->oprsp_conn.con_src),
+ sizeof(saddr));
+ spans_result_str(&oprsp_p->oprsp_result, result_str);
+ printf("result=%s, daddr=%s, saddr=%s, dsap=%d, ssap=%d, vp.vc=%d.%d",
+ result_str, daddr, saddr,
+ oprsp_p->oprsp_conn.con_dsap,
+ oprsp_p->oprsp_conn.con_ssap,
+ SPANS_EXTRACT_VPI(oprsp_p->oprsp_vpvc),
+ SPANS_EXTRACT_VCI(oprsp_p->oprsp_vpvc));
+ break;
+ case SPANS_OPEN_CNF:
+ opcnf_p = &objp->spans_msgbody_u.mb_open_cnf;
+ strncpy(daddr, spans_addr_print(&opcnf_p->opcnf_conn.con_dst),
+ sizeof(daddr));
+ strncpy(saddr, spans_addr_print(&opcnf_p->opcnf_conn.con_src),
+ sizeof(saddr));
+ spans_result_str(&opcnf_p->opcnf_result, result_str);
+ printf("result=%s, daddr=%s, saddr=%s, dsap=%d, ssap=%d, vp.vc=%d.%d",
+ result_str, daddr, saddr,
+ opcnf_p->opcnf_conn.con_dsap,
+ opcnf_p->opcnf_conn.con_ssap,
+ SPANS_EXTRACT_VPI(opcnf_p->opcnf_vpvc),
+ SPANS_EXTRACT_VCI(opcnf_p->opcnf_vpvc));
+ break;
+ case SPANS_CLOSE_REQ:
+ clreq_p = &objp->spans_msgbody_u.mb_close_req;
+ strncpy(daddr, spans_addr_print(&clreq_p->clreq_conn.con_dst),
+ sizeof(daddr));
+ strncpy(saddr, spans_addr_print(&clreq_p->clreq_conn.con_src),
+ sizeof(saddr));
+ printf("daddr=%s, saddr=%s, dsap=%d, ssap=%d",
+ daddr, saddr,
+ clreq_p->clreq_conn.con_dsap,
+ clreq_p->clreq_conn.con_ssap);
+ break;
+ case SPANS_CLOSE_IND:
+ clind_p = &objp->spans_msgbody_u.mb_close_ind;
+ strncpy(daddr, spans_addr_print(&clind_p->clind_conn.con_dst),
+ sizeof(daddr));
+ strncpy(saddr, spans_addr_print(&clind_p->clind_conn.con_src),
+ sizeof(saddr));
+ printf("daddr=%s, saddr=%s, dsap=%d, ssap=%d",
+ daddr, saddr,
+ clind_p->clind_conn.con_dsap,
+ clind_p->clind_conn.con_ssap);
+ break;
+ case SPANS_CLOSE_RSP:
+ clrsp_p = &objp->spans_msgbody_u.mb_close_rsp;
+ strncpy(daddr, spans_addr_print(&clrsp_p->clrsp_conn.con_dst),
+ sizeof(daddr));
+ strncpy(saddr, spans_addr_print(&clrsp_p->clrsp_conn.con_src),
+ sizeof(saddr));
+ spans_result_str(&clrsp_p->clrsp_result, result_str);
+ printf("result=%s, daddr=%s, saddr=%s, dsap=%d, ssap=%d",
+ result_str, daddr, saddr,
+ clrsp_p->clrsp_conn.con_dsap,
+ clrsp_p->clrsp_conn.con_ssap);
+ break;
+ case SPANS_CLOSE_CNF:
+ clcnf_p = &objp->spans_msgbody_u.mb_close_cnf;
+ strncpy(daddr, spans_addr_print(&clcnf_p->clcnf_conn.con_dst),
+ sizeof(daddr));
+ strncpy(saddr, spans_addr_print(&clcnf_p->clcnf_conn.con_src),
+ sizeof(saddr));
+ spans_result_str(&clcnf_p->clcnf_result, result_str);
+ printf("result=%s, daddr=%s, saddr=%s, dsap=%d, ssap=%d",
+ result_str, daddr, saddr,
+ clcnf_p->clcnf_conn.con_dsap,
+ clcnf_p->clcnf_conn.con_ssap);
+ break;
+ case SPANS_RCLOSE_REQ:
+ rcreq_p = &objp->spans_msgbody_u.mb_rclose_req;
+ strncpy(daddr, spans_addr_print(&rcreq_p->rcreq_conn.con_dst),
+ sizeof(daddr));
+ strncpy(saddr, spans_addr_print(&rcreq_p->rcreq_conn.con_src),
+ sizeof(saddr));
+ printf("daddr=%s, saddr=%s, dsap=%d, ssap=%d",
+ daddr, saddr,
+ rcreq_p->rcreq_conn.con_dsap,
+ rcreq_p->rcreq_conn.con_ssap);
+ break;
+ case SPANS_RCLOSE_IND:
+ rcind_p = &objp->spans_msgbody_u.mb_rclose_ind;
+ strncpy(daddr, spans_addr_print(&rcind_p->rcind_conn.con_dst),
+ sizeof(daddr));
+ strncpy(saddr, spans_addr_print(&rcind_p->rcind_conn.con_src),
+ sizeof(saddr));
+ printf("daddr=%s, saddr=%s, dsap=%d, ssap=%d",
+ daddr, saddr,
+ rcind_p->rcind_conn.con_dsap,
+ rcind_p->rcind_conn.con_ssap);
+ break;
+ case SPANS_RCLOSE_RSP:
+ rcrsp_p = &objp->spans_msgbody_u.mb_rclose_rsp;
+ strncpy(daddr, spans_addr_print(&rcrsp_p->rcrsp_conn.con_dst),
+ sizeof(daddr));
+ strncpy(saddr, spans_addr_print(&rcrsp_p->rcrsp_conn.con_src),
+ sizeof(saddr));
+ spans_result_str(&rcrsp_p->rcrsp_result, result_str);
+ printf("result=%s, daddr=%s, saddr=%s, dsap=%d, ssap=%d",
+ result_str, daddr, saddr,
+ rcrsp_p->rcrsp_conn.con_dsap,
+ rcrsp_p->rcrsp_conn.con_ssap);
+ break;
+ case SPANS_RCLOSE_CNF:
+ rccnf_p = &objp->spans_msgbody_u.mb_rclose_cnf;
+ strncpy(daddr, spans_addr_print(&rccnf_p->rccnf_conn.con_dst),
+ sizeof(daddr));
+ strncpy(saddr, spans_addr_print(&rccnf_p->rccnf_conn.con_src),
+ sizeof(saddr));
+ spans_result_str(&rccnf_p->rccnf_result, result_str);
+ printf("result=%s, daddr=%s, saddr=%s, dsap=%d, ssap=%d",
+ result_str, daddr, saddr,
+ rccnf_p->rccnf_conn.con_dsap,
+ rccnf_p->rccnf_conn.con_ssap);
+ break;
+ }
+ printf("\n");
+}
+
+void
+spans_print_msg(objp)
+ spans_msg *objp;
+{
+ spans_indent = INIT_INDENT;
+ spans_print_msgbody(&objp->sm_body);
+}
+
+#endif /* ifdef LONGPRINT */
diff --git a/sys/netatm/spans/spans_proto.c b/sys/netatm/spans/spans_proto.c
new file mode 100644
index 0000000..e298ed8
--- /dev/null
+++ b/sys/netatm/spans/spans_proto.c
@@ -0,0 +1,558 @@
+/*
+ *
+ * ===================================
+ * 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: spans_proto.c,v 1.7 1998/08/26 23:29:10 mks Exp $
+ *
+ */
+
+/*
+ * SPANS Signalling Manager
+ * ---------------------------
+ *
+ * SPANS protocol processing module.
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: spans_proto.c,v 1.7 1998/08/26 23:29:10 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include "spans_xdr.h"
+#include <netatm/spans/spans_var.h>
+
+/*
+ * Internal functions
+ */
+caddr_t spans_getname __P((void *));
+void spans_connected __P((void *));
+void spans_cleared __P((void *, struct t_atm_cause *));
+void spans_cpcs_data __P((void *, KBuffer *));
+
+
+/*
+ * ATM endpoint for SPANS signalling channel
+ */
+static Atm_endpoint spans_endpt = {
+ NULL, /* ep_next */
+ ENDPT_SPANS_SIG, /* ep_id */
+ NULL, /* ep_ioctl */
+ spans_getname, /* ep_getname */
+ spans_connected, /* ep_connected */
+ spans_cleared, /* ep_cleared */
+ NULL, /* ep_incoming */
+ NULL, /* ep_addparty */
+ NULL, /* ep_dropparty */
+ NULL, /* ep_cpcs_ctl */
+ spans_cpcs_data, /* ep_cpcs_data */
+ NULL, /* ep_saal_ctl */
+ NULL, /* ep_saal_data */
+ NULL, /* ep_sscop_ctl */
+ NULL /* ep_sscop_data */
+};
+
+
+/*
+ * ATM connection attributes for UNI signalling channel
+ */
+static Atm_attributes spans_attr = {
+ NULL, /* nif */
+ CMAPI_CPCS, /* api */
+ 0, /* api_init */
+ 0, /* headin */
+ 0, /* headout */
+ { /* aal */
+ T_ATM_PRESENT, /* aal.tag */
+ ATM_AAL3_4 /* aal.aal_type */
+ },
+ { /* traffic */
+ T_ATM_PRESENT, /* traffic.tag */
+ { /* traffic.v */
+ { /* traffic.v.forward */
+ T_ATM_ABSENT, /* PCR_high */
+ 0, /* PCR_all */
+ T_ATM_ABSENT, /* SCR_high */
+ T_ATM_ABSENT, /* SCR_all */
+ T_ATM_ABSENT, /* MBS_high */
+ T_ATM_ABSENT, /* MBS_all */
+ T_NO, /* tagging */
+ },
+ { /* traffic.v.backward */
+ T_ATM_ABSENT, /* PCR_high */
+ 0, /* PCR_all */
+ T_ATM_ABSENT, /* SCR_high */
+ T_ATM_ABSENT, /* SCR_all */
+ T_ATM_ABSENT, /* MBS_high */
+ T_ATM_ABSENT, /* MBS_all */
+ T_NO, /* tagging */
+ },
+ T_YES, /* best_effort */
+ }
+ },
+ { /* bearer */
+ T_ATM_PRESENT, /* bearer.tag */
+ { /* bearer.v */
+ T_ATM_CLASS_X, /* class */
+ T_ATM_NULL, /* traffic_type */
+ T_ATM_NO_END_TO_END, /* timing_req */
+ T_NO, /* clipping */
+ T_ATM_1_TO_1, /* conn_conf */
+ }
+ },
+ { /* bhli */
+ T_ATM_ABSENT, /* bhli.tag */
+ },
+ { /* blli */
+ T_ATM_ABSENT, /* blli.tag_l2 */
+ T_ATM_ABSENT, /* blli.tag_l3 */
+ },
+ { /* llc */
+ T_ATM_ABSENT, /* llc.tag */
+ },
+ { /* called */
+ T_ATM_PRESENT, /* called.tag */
+ },
+ { /* calling */
+ T_ATM_ABSENT, /* calling.tag */
+ },
+ { /* qos */
+ T_ATM_PRESENT, /* qos.tag */
+ { /* qos.v */
+ T_ATM_NETWORK_CODING, /* coding_standard */
+ { /* qos.v.forward */
+ T_ATM_QOS_CLASS_0, /* class */
+ },
+ { /* qos.v.backward */
+ T_ATM_QOS_CLASS_0, /* class */
+ }
+ }
+ },
+ { /* transit */
+ T_ATM_ABSENT, /* transit.tag */
+ },
+ { /* cause */
+ T_ATM_ABSENT, /* cause.tag */
+ }
+};
+
+
+/*
+ * SPANS cause structre
+ */
+struct t_atm_cause spans_cause = {
+ T_ATM_ITU_CODING, /* coding_standard */
+ T_ATM_LOC_USER, /* location */
+ T_ATM_CAUSE_UNSPECIFIED_NORMAL, /* cause_value */
+ { 0, 0, 0, 0 } /* diagnostics */
+};
+
+
+/*
+ * Process a SPANS timeout
+ *
+ * Called when a previously scheduled spans control block timer expires.
+ * Processing will based on the current SPANS state.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * tip pointer to spans timer control block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+spans_timer(tip)
+ struct atm_time *tip;
+{
+ struct spans *spp;
+ spans_msg *msg;
+ Atm_addr_pvc *pvcp;
+ int err;
+
+ /*
+ * Back-off to SPANS control block
+ */
+ spp = (struct spans *)
+ ((caddr_t)tip - (int)(&((struct spans *)0)->sp_time));
+
+ ATM_DEBUG2("spans_timer: spp=0x%x,state=%d\n",
+ (int)spp, spp->sp_state);
+
+ /*
+ * Process timeout based on protocol state
+ */
+ switch (spp->sp_state) {
+
+ case SPANS_INIT:
+
+ /*
+ * Open signalling channel
+ */
+ spans_attr.nif = spp->sp_pif->pif_nif;
+
+ spans_attr.aal.v.aal4.forward_max_SDU_size =
+ ATM_NIF_MTU;
+ spans_attr.aal.v.aal4.backward_max_SDU_size =
+ ATM_NIF_MTU;
+ spans_attr.aal.v.aal4.SSCS_type =
+ T_ATM_SSCS_SSCOP_UNREL;
+ spans_attr.aal.v.aal4.mid_low = 0;
+ spans_attr.aal.v.aal4.mid_high = 0;
+
+ spans_attr.called.tag = T_ATM_PRESENT;
+ spans_attr.called.addr.address_format = T_ATM_PVC_ADDR;
+ spans_attr.called.addr.address_length =
+ sizeof(Atm_addr_pvc);
+ pvcp = (Atm_addr_pvc *)spans_attr.called.addr.address;
+ ATM_PVC_SET_VPI(pvcp, SPANS_SIG_VPI);
+ ATM_PVC_SET_VCI(pvcp, SPANS_SIG_VCI);
+ spans_attr.called.subaddr.address_format = T_ATM_ABSENT;
+ spans_attr.called.subaddr.address_length = 0;
+
+ spans_attr.traffic.v.forward.PCR_all_traffic =
+ spp->sp_pif->pif_pcr;
+ spans_attr.traffic.v.backward.PCR_all_traffic =
+ spp->sp_pif->pif_pcr;
+
+ err = atm_cm_connect(&spans_endpt, spp, &spans_attr,
+ &spp->sp_conn);
+ if (err) {
+ log(LOG_CRIT, "spans: signalling channel setup failed\n");
+ return;
+ }
+
+ /*
+ * Signalling channel open, start probing
+ */
+ spp->sp_state = SPANS_PROBE;
+
+ /* FALLTHRU */
+
+ case SPANS_PROBE:
+ case SPANS_ACTIVE:
+
+ /*
+ * Send out SPANS_STAT_REQ message
+ */
+ msg = (spans_msg *)atm_allocate(&spans_msgpool);
+ if (msg == NULL) {
+ /* Retry later if no memory */
+ SPANS_TIMER(spp, SPANS_PROBE_ERR_WAIT);
+ break;
+ }
+ msg->sm_vers = SPANS_VERS_1_0;
+ msg->sm_type = SPANS_STAT_REQ;
+ msg->sm_stat_req.streq_es_epoch = spp->sp_h_epoch;
+ if (spans_send_msg(spp, msg)) {
+ /* Retry later if send fails */
+ SPANS_TIMER(spp, SPANS_PROBE_ERR_WAIT);
+ atm_free(msg);
+ break;
+ }
+ atm_free(msg);
+ spp->sp_probe_ct++;
+
+ /*
+ * Check whether we're getting an answer to our probes
+ */
+ if (spp->sp_state == SPANS_ACTIVE &&
+ spp->sp_probe_ct > SPANS_PROBE_THRESH) {
+ /*
+ * Interface is down, notify VCC owners
+ */
+ spans_switch_reset(spp, SPANS_UNI_DOWN);
+
+ /*
+ * Set new state and increment host epoch so
+ * switch knows we reset everyting.
+ */
+ spp->sp_state = SPANS_PROBE;
+ spp->sp_h_epoch++;
+ spp->sp_s_epoch = 0;
+ }
+
+ /*
+ * Keep sending status requests
+ */
+ SPANS_TIMER(spp, SPANS_PROBE_INTERVAL);
+
+ break;
+
+ case SPANS_DETACH:
+ /*
+ * Try to terminate the SPANS signalling PVC
+ */
+ err = atm_cm_release(spp->sp_conn, &spans_cause);
+ if (err) {
+ log(LOG_ERR, "spans: can't close signalling channel\n");
+ }
+ break;
+
+ default:
+ log(LOG_ERR, "spans: timer state: spp=0x%x, state=%d\n",
+ (int)spp, spp->sp_state);
+ }
+}
+
+
+/*
+ * Process a SPANS VCC timeout
+ *
+ * Called when a previously scheduled SPANS VCCB timer expires.
+ * Processing will based on the current VCC state.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * tip pointer to vccb timer control block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+spans_vctimer(tip)
+ struct atm_time *tip;
+{
+ int err;
+ struct spans *spp;
+ struct spans_vccb *svp;
+
+ /*
+ * Get VCCB and SPANS control block addresses
+ */
+ svp = (struct spans_vccb *) ((caddr_t)tip -
+ (int)(&((struct vccb *)0)->vc_time));
+ spp = (struct spans *)svp->sv_pif->pif_siginst;
+
+ ATM_DEBUG3("spans_vctimer: svp=0x%x, sstate=%d, ustate=%d\n",
+ (int)svp, svp->sv_sstate, svp->sv_ustate);
+
+ /*
+ * Process timeout based on protocol state
+ */
+ switch (svp->sv_sstate) {
+
+ case SPANS_VC_ABORT:
+ /*
+ * Kill the VCCB and notify the owner
+ */
+ err = spans_clear_vcc(spp, svp);
+ break;
+
+ case SPANS_VC_FREE:
+ /*
+ * Free VCCB storage
+ */
+ svp->sv_ustate = VCCU_CLOSED;
+ svp->sv_sstate = SPANS_VC_FREE;
+ spans_free((struct vccb *)svp);
+ break;
+
+ case SPANS_VC_POPEN:
+ /*
+ * Issued open request, but didn't get response.
+ */
+ if (svp->sv_retry < SV_MAX_RETRY) {
+ /*
+ * Retransmit the open request
+ */
+ err = spans_send_open_req(spp, svp);
+ svp->sv_retry++;
+ SPANS_VC_TIMER((struct vccb *) svp, SV_TIMEOUT);
+ } else {
+ /*
+ * Retry limit exceeded--report the open failed
+ */
+ svp->sv_ustate = VCCU_CLOSED;
+ svp->sv_sstate = SPANS_VC_FREE;
+ svp->sv_connvc->cvc_attr.cause.tag =
+ T_ATM_PRESENT;
+ svp->sv_connvc->cvc_attr.cause.v.coding_standard =
+ T_ATM_ITU_CODING;
+ svp->sv_connvc->cvc_attr.cause.v.location =
+ T_ATM_LOC_USER;
+ svp->sv_connvc->cvc_attr.cause.v.cause_value =
+ T_ATM_CAUSE_NO_USER_RESPONDING;
+ KM_ZERO(svp->sv_connvc->cvc_attr.cause.v.diagnostics,
+ sizeof(svp->sv_connvc->cvc_attr.cause.v.diagnostics));
+ atm_cm_cleared(svp->sv_connvc);
+ }
+ break;
+
+ case SPANS_VC_CLOSE:
+ /*
+ * Issued close request, but didn't get response.
+ */
+ if (svp->sv_retry < SV_MAX_RETRY) {
+ /*
+ * Retransmit the close request
+ */
+ err = spans_send_close_req(spp, svp);
+ svp->sv_retry++;
+ SPANS_VC_TIMER((struct vccb *) svp, SV_TIMEOUT);
+ } else {
+ /*
+ * Retry limit exceeded--just finish the close
+ */
+ svp->sv_sstate = SPANS_VC_FREE;
+ svp->sv_connvc->cvc_attr.cause.tag = T_ATM_PRESENT;
+ svp->sv_connvc->cvc_attr.cause.v.coding_standard =
+ T_ATM_ITU_CODING;
+ svp->sv_connvc->cvc_attr.cause.v.location =
+ T_ATM_LOC_USER;
+ svp->sv_connvc->cvc_attr.cause.v.cause_value =
+ T_ATM_CAUSE_NO_USER_RESPONDING;
+ KM_ZERO(svp->sv_connvc->cvc_attr.cause.v.diagnostics,
+ sizeof(svp->sv_connvc->cvc_attr.cause.v.diagnostics));
+ atm_cm_cleared(svp->sv_connvc);
+ }
+ break;
+
+ case SPANS_VC_ACTIVE:
+ case SPANS_VC_ACT_DOWN:
+ /*
+ * Shouldn't happen
+ */
+ log(LOG_ERR, "spans_vctimer: unexpected state %d\n",
+ svp->sv_sstate);
+ break;
+
+ default:
+ log(LOG_ERR, "spans: vctimer state: svp=0x%x, sstate=%d\n",
+ (int)svp, svp->sv_sstate);
+ }
+}
+
+
+/*
+ * SPANS name routine
+ *
+ * Arguments:
+ * tok SPANS signalling channel token (ignored)
+ *
+ * Returns:
+ * pointer to a string identifying the SPANS signalling manager
+ *
+ */
+caddr_t
+spans_getname(tok)
+ void *tok;
+{
+ return("SPANS");
+}
+
+
+/*
+ * Process a VCC connection notification
+ *
+ * Should never be called
+ *
+ * Arguments:
+ * tok user's connection token (SPANS protocol block)
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+spans_connected(tok)
+ void *tok;
+{
+ struct spans *spp = (struct spans *)tok;
+
+ ATM_DEBUG2("spans_connected: spp=0x%x,state=%d\n",
+ (int)spp, spp->sp_state);
+
+ /*
+ * Connected routine shouldn't ever get called for a PVC
+ */
+ log(LOG_ERR, "spans: connected function called, tok=0x%x\n",
+ (int)spp);
+}
+
+
+/*
+ * Process a VCC close notification
+ *
+ * Called when the SPANS signalling channel is closed
+ *
+ * Arguments:
+ * tok user's connection token (spans protocol block)
+ * cp pointer to cause structure
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+spans_cleared(tok, cp)
+ void *tok;
+ struct t_atm_cause *cp;
+{
+ struct spans *spp = (struct spans *)tok;
+
+ /*
+ * VCC has been closed.
+ */
+ log(LOG_ERR, "spans: signalling channel closed\n");
+ SPANS_CANCEL(spp);
+ spp->sp_conn = 0;
+}
+
+
+/*
+ * SPANS CPCS data handler
+ *
+ * This is the module which receives data on the SPANS signalling
+ * channel. Processing is based on the indication received from the
+ * AAL and the protocol state.
+ *
+ * Arguments:
+ * tok session token (pointer to spans protocol control block)
+ * m pointer to buffer with data
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+spans_cpcs_data(tok, m)
+ void *tok;
+ KBuffer *m;
+{
+ struct spans *spp = tok;
+
+ ATM_DEBUG3("spans_cpcs_data: spp=0x%x,state=%d,m=0x%x,\n",
+ (int)spp, spp->sp_state, m);
+
+ /*
+ * Process data
+ */
+ spans_rcv_msg(spp, m);
+}
diff --git a/sys/netatm/spans/spans_subr.c b/sys/netatm/spans/spans_subr.c
new file mode 100644
index 0000000..48b9705
--- /dev/null
+++ b/sys/netatm/spans/spans_subr.c
@@ -0,0 +1,494 @@
+/*
+ *
+ * ===================================
+ * 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: spans_subr.c,v 1.9 1998/08/26 23:29:10 mks Exp $
+ *
+ */
+
+/*
+ * SPANS Signalling Manager
+ * ---------------------------
+ *
+ * SPANS-related subroutines.
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: spans_subr.c,v 1.9 1998/08/26 23:29:10 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include "spans_xdr.h"
+#include <netatm/spans/spans_var.h>
+
+
+/*
+ * Open a SPANS VCC
+ *
+ * Called when a user wants to open a VC. This function will construct
+ * a VCCB, create the stack requested by the user, and, if we are
+ * opening an SVC, start the SPANS signalling message exchange. The
+ * user will have to wait for a notify event to be sure the SVC is fully
+ * open.
+ *
+ * Must be called at splnet.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance
+ * acp pointer to PVC's connection parameters
+ *
+ * Returns:
+ * 0 VCC creation successful
+ * errno VCC setup failed - reason indicated
+ *
+ */
+int
+spans_open_vcc(spp, cvp)
+ struct spans *spp;
+ Atm_connvc *cvp;
+
+{
+ struct atm_pif *pip = spp->sp_pif;
+ struct spans_vccb *svp;
+ Atm_addr_pvc *pvp;
+ spans_aal aal;
+ int err, pvc, vpi, vci;
+
+ ATM_DEBUG2("spans_open_vcc: spp=0x%x, cvp=0x%x\n", spp, cvp);
+
+ /*
+ * Validate user parameters. AAL and encapsulation are
+ * checked by the connection manager.
+ */
+
+ /*
+ * Check called party address(es)
+ */
+ if (cvp->cvc_attr.called.tag != T_ATM_PRESENT ||
+ cvp->cvc_attr.called.addr.address_format ==
+ T_ATM_ABSENT ||
+ cvp->cvc_attr.called.subaddr.address_format !=
+ T_ATM_ABSENT) {
+ return(EINVAL);
+ }
+ switch (cvp->cvc_attr.called.addr.address_format) {
+ case T_ATM_PVC_ADDR:
+ /*
+ * Make sure VPI/VCI is valid
+ */
+ pvc = 1;
+ pvp = (Atm_addr_pvc *)cvp->cvc_attr.called.addr.address;
+ vpi = ATM_PVC_GET_VPI(pvp);
+ vci = ATM_PVC_GET_VCI(pvp);
+ if ((vpi > pip->pif_maxvpi) ||
+ (vci == 0) ||
+ (vci > pip->pif_maxvci)) {
+ return(ERANGE);
+ }
+
+ /*
+ * Make sure VPI/VCI is not already in use
+ */
+ if (spans_find_vpvc(spp, vpi, vci, 0)) {
+ return(EADDRINUSE);
+ }
+ ATM_DEBUG2("spans_open_vcc: VPI.VCI=%d.%d\n",
+ vpi, vci);
+ break;
+
+ case T_ATM_SPANS_ADDR:
+ pvc = 0;
+ vpi = vci = 0;
+
+ /*
+ * Check signalling state
+ */
+ if (spp->sp_state != SPANS_ACTIVE) {
+ return(ENETDOWN);
+ }
+
+ /*
+ *Check destination address length
+ */
+ if (cvp->cvc_attr.called.addr.address_length !=
+ sizeof(spans_addr)) {
+ return(EINVAL);
+ }
+ break;
+
+ default:
+ return(EINVAL);
+ }
+
+ /*
+ * Check that this is for the same interface SPANS uses
+ */
+ if (!cvp->cvc_attr.nif ||
+ cvp->cvc_attr.nif->nif_pif != spp->sp_pif) {
+ return(EINVAL);
+ }
+
+ /*
+ * Check AAL
+ */
+ if (!spans_get_spans_aal(cvp->cvc_attr.aal.type, &aal)) {
+ return(EINVAL);
+ }
+
+#ifdef NOTDEF
+ /*
+ * Check encapsulation
+ */
+ /* XXX -- How do we check encapsulation? */
+ if (cvp->ac_encaps != ATM_ENC_NULL) {
+ return(EINVAL);
+ }
+#endif
+
+ /*
+ * Allocate control block for VCC
+ */
+ svp = (struct spans_vccb *)atm_allocate(&spans_vcpool);
+ if (svp == NULL) {
+ return(ENOMEM);
+ }
+
+ /*
+ * Fill in VCCB
+ */
+ if (pvc) {
+ svp->sv_type = VCC_PVC | VCC_IN | VCC_OUT;
+ svp->sv_vpi = vpi;
+ svp->sv_vci = vci;
+ svp->sv_sstate = (spp->sp_state == SPANS_ACTIVE ?
+ SPANS_VC_ACTIVE : SPANS_VC_ACT_DOWN);
+ svp->sv_ustate = VCCU_OPEN;
+ } else {
+ svp->sv_type = VCC_SVC | VCC_OUT;
+ spans_addr_copy(cvp->cvc_attr.called.addr.address,
+ &svp->sv_conn.con_dst);
+ spans_addr_copy(spp->sp_addr.address,
+ &svp->sv_conn.con_src);
+ svp->sv_conn.con_dsap = SPANS_SAP_IP;
+ svp->sv_conn.con_ssap = spans_ephemeral_sap(spp);
+ svp->sv_sstate = SPANS_VC_POPEN;
+ svp->sv_ustate = VCCU_POPEN;
+ }
+ svp->sv_proto = ATM_SIG_SPANS;
+ svp->sv_pif = spp->sp_pif;
+ svp->sv_nif = cvp->cvc_attr.nif;
+ svp->sv_connvc = cvp;
+ svp->sv_spans_aal = aal;
+ svp->sv_tstamp = time_second;
+
+ /*
+ * Put VCCB on SPANS queue
+ */
+ ENQUEUE(svp, struct spans_vccb, sv_sigelem, spp->sp_vccq);
+
+ /*
+ * Link VCCB to VCC connection block
+ */
+ cvp->cvc_vcc = (struct vccb *) svp;
+
+ /*
+ * Start the SPANS message exchange if this is an SVC
+ */
+ if (!pvc) {
+ svp->sv_retry = 0;
+ svp->sv_spans_qos.rsc_peak = 1;
+ svp->sv_spans_qos.rsc_mean = 1;
+ svp->sv_spans_qos.rsc_burst = 1;
+ err = spans_send_open_req(spp, svp);
+ if (err) {
+ /*
+ * On error, delete the VCCB
+ */
+ DEQUEUE(svp, struct spans_vccb, sv_sigelem,
+ spp->sp_vccq);
+ cvp->cvc_vcc = (struct vccb *)0;
+ atm_free((caddr_t)svp);
+ return(err);
+ } else {
+ /*
+ * VCCB is opening--set the retransmit timer
+ */
+ SPANS_VC_TIMER((struct vccb *) svp, SV_TIMEOUT);
+ }
+ }
+
+ return(0);
+}
+
+
+/*
+ * Close a SPANS VCC
+ *
+ * Called when a user wants to close a VCC. This function will clean
+ * up the VCCB and, for an SVC, send a close request.
+ *
+ * Must be called at splnet.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance
+ * svp pointer to VCCB for the VCC to be closed
+ *
+ * Returns:
+ * 0 VCC is now closed
+ * errno error encountered
+ */
+int
+spans_close_vcc(spp, svp, force)
+ struct spans *spp;
+ struct spans_vccb *svp;
+ int force;
+
+{
+ int err = 0;
+
+ ATM_DEBUG2("spans_close_vcc: svp=0x%x, state=%d\n", svp,
+ svp->sv_sstate);
+
+ /*
+ * Check that this is for the same interface SPANS uses
+ */
+ if (svp->sv_pif != spp->sp_pif) {
+ return (EINVAL);
+ }
+
+ /*
+ * Kill any possible timer
+ */
+ SPANS_VC_CANCEL((struct vccb *) svp);
+
+ /*
+ * Mark the close time.
+ */
+ svp->sv_tstamp = time_second;
+
+ /*
+ * Process based on the connection type
+ */
+ if (svp->sv_type & VCC_PVC) {
+ svp->sv_sstate = SPANS_VC_FREE;
+ svp->sv_ustate = VCCU_CLOSED;
+ } else if (svp->sv_type & VCC_SVC) {
+ /*
+ * Update VCCB states
+ */
+ svp->sv_ustate = VCCU_CLOSED;
+
+ /*
+ * Send the appropriate SPANS close message
+ */
+ switch (svp->sv_sstate) {
+ case SPANS_VC_R_POPEN:
+ err = spans_send_open_rsp(spp, svp, SPANS_FAIL);
+ svp->sv_sstate = SPANS_VC_FREE;
+ break;
+ case SPANS_VC_OPEN:
+ case SPANS_VC_POPEN:
+ case SPANS_VC_ABORT:
+ svp->sv_retry = 0;
+ err = spans_send_close_req(spp, svp);
+ if (force) {
+ svp->sv_sstate = SPANS_VC_FREE;
+ } else {
+ svp->sv_sstate = SPANS_VC_CLOSE;
+ SPANS_VC_TIMER((struct vccb *) svp,
+ SV_TIMEOUT);
+ }
+ break;
+ case SPANS_VC_CLOSE:
+ if (force) {
+ svp->sv_sstate = SPANS_VC_FREE;
+ }
+ break;
+ }
+ }
+
+ /*
+ * Wait for user to free resources
+ */
+ return(err);
+}
+
+
+/*
+ * Clear a SPANS VCC
+ *
+ * Called when the signalling manager wants to close a VCC immediately.
+ * This function will clean up the VCCB and notify the owner.
+ *
+ * Must be called at splnet.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance
+ * svp pointer to VCCB for the VCC to be closed
+ *
+ * Returns:
+ * 0 VCC is now closed
+ * errno error encountered
+ */
+int
+spans_clear_vcc(spp, svp)
+ struct spans *spp;
+ struct spans_vccb *svp;
+
+{
+ u_char outstate;
+
+ ATM_DEBUG2("spans_clear_vcc: svp=0x%x, state=%d\n", svp,
+ svp->sv_sstate);
+
+ /*
+ * Check that this is for the same interface SPANS uses
+ */
+ if (svp->sv_pif != spp->sp_pif) {
+ return (EINVAL);
+ }
+
+ /*
+ * Kill any possible timer
+ */
+ SPANS_VC_CANCEL((struct vccb *) svp);
+
+ /*
+ * Mark the close time
+ */
+ svp->sv_tstamp = time_second;
+
+ /*
+ * Mark the VCCB closed
+ */
+ outstate = svp->sv_sstate;
+ svp->sv_sstate = SPANS_VC_FREE;
+ svp->sv_ustate = VCCU_CLOSED;
+
+ /*
+ * Notify the user if old state indicates.
+ */
+ switch (outstate) {
+ case SPANS_VC_ACTIVE:
+ case SPANS_VC_ACT_DOWN:
+ case SPANS_VC_POPEN:
+ case SPANS_VC_OPEN:
+ case SPANS_VC_CLOSE:
+ case SPANS_VC_ABORT:
+ /* XXX -- set cause */
+ atm_cm_cleared(svp->sv_connvc);
+ break;
+ case SPANS_VC_NULL:
+ case SPANS_VC_R_POPEN:
+ case SPANS_VC_FREE:
+ break;
+ }
+
+ /*
+ * Wait for user to free resources
+ */
+ return(0);
+}
+
+
+/*
+ * Reset the switch state
+ *
+ * Called when the switch or host at the far end of the ATM link has
+ * gone away. This can be deteched either by a number of SPANS_STAT_REQ
+ * messages going unanswered or by the host epoch changing in a SPANS
+ * SPANS_STAT_IND or SPANS_STAT_REQ message.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+spans_switch_reset(spp, cause)
+ struct spans *spp;
+ int cause;
+
+{
+ int s;
+ struct vccb *vcp, *vnext;
+
+ ATM_DEBUG2("spans_switch_reset: spp=0x%x, cause=%d\n",
+ spp, cause);
+
+ /*
+ * Log the event
+ */
+ log(LOG_INFO, "spans: signalling %s on interface %s%d\n",
+ (cause == SPANS_UNI_DOWN ? "down" : "up"),
+ spp->sp_pif->pif_name,
+ spp->sp_pif->pif_unit);
+
+ /*
+ * Terminate all of our VCCs
+ */
+ s = splnet();
+ for (vcp = Q_HEAD(spp->sp_vccq, struct vccb); vcp;
+ vcp = vnext) {
+
+ u_char outstate;
+
+ vnext = Q_NEXT(vcp, struct vccb, vc_sigelem);
+
+ if (vcp->vc_type & VCC_SVC) {
+ /*
+ * Close the SVC and notify the owner
+ */
+ outstate = vcp->vc_sstate;
+ SPANS_VC_CANCEL((struct vccb *) vcp);
+ vcp->vc_ustate = VCCU_CLOSED;
+ vcp->vc_sstate = SPANS_VC_FREE;
+ if (outstate == SPANS_VC_OPEN ||
+ outstate == SPANS_VC_POPEN) {
+ /* XXX -- set cause */
+ atm_cm_cleared(vcp->vc_connvc);
+ }
+ } else if (vcp->vc_type & VCC_PVC) {
+ /*
+ * Note new state
+ */
+ switch(cause) {
+ case SPANS_UNI_DOWN:
+ vcp->vc_sstate = SPANS_VC_ACT_DOWN;
+ break;
+ case SPANS_UNI_UP:
+ vcp->vc_sstate = SPANS_VC_ACTIVE;
+ break;
+ }
+ } else {
+ log(LOG_ERR, "spans: invalid VCC type: vccb=0x%x, type=%d\n",
+ vcp, vcp->vc_type);
+ }
+ }
+ (void) splx(s);
+}
diff --git a/sys/netatm/spans/spans_util.c b/sys/netatm/spans/spans_util.c
new file mode 100644
index 0000000..6d470e1
--- /dev/null
+++ b/sys/netatm/spans/spans_util.c
@@ -0,0 +1,477 @@
+/*
+ *
+ * ===================================
+ * 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: spans_util.c,v 1.6 1998/08/26 23:29:10 mks Exp $
+ *
+ */
+
+/*
+ * SPANS Signalling Manager
+ * ---------------------------
+ *
+ * SPANS-related utility routines.
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: spans_util.c,v 1.6 1998/08/26 23:29:10 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include "spans_xdr.h"
+#include <netatm/spans/spans_var.h>
+
+
+#ifdef NOTDEF
+/* XXX -- Remove all SAP checks? */
+#define MAX_SAP_ENT 1
+static struct {
+ spans_sap spans_sap;
+ Sap_t local_sap;
+} sap_table[MAX_SAP_ENT] = {
+ {SPANS_SAP_IP, SAP_IP},
+};
+
+
+/*
+ * Translate an internal SAP to a SPANS SAP
+ *
+ * Search the SAP table for the given SAP. Put the corresponding SPANS
+ * SAP into the indicated variable.
+ *
+ * Arguments:
+ * lsap the value of the internal SAP
+ * ssap a pointer to the variable to receive the SPANS SAP value
+ *
+ * Returns:
+ * TRUE the SAP was found; *ssap is valid
+ * FALSE the SAP was not found; *ssap is not valid
+ *
+ */
+int
+spans_get_spans_sap(lsap, ssap)
+ Sap_t lsap;
+ spans_sap *ssap;
+{
+ int i;
+
+ /*
+ * Search the SAP table for the given local SAP
+ */
+ for (i=0; i< MAX_SAP_ENT; i++) {
+ if (sap_table[i].local_sap == lsap) {
+ *ssap = sap_table[i].spans_sap;
+ return(TRUE);
+ }
+ }
+ return(FALSE);
+}
+
+
+/*
+ * Translate a SPANS SAP to internal format
+ *
+ * Search the SAP table for the given SAP. Put the corresponding
+ * internal SAP into the indicated variable.
+ *
+ * Arguments:
+ * ssap the value of the SPANS SAP
+ * lsap a pointer to the variable to receive the internal
+ * SAP value
+ *
+ * Returns:
+ * TRUE the SAP was found; *lsap is valid
+ * FALSE the SAP was not found; *lsap is not valid
+ *
+ */
+int
+spans_get_local_sap(ssap, lsap)
+ spans_sap ssap;
+ Sap_t *lsap;
+{
+ int i;
+
+ /*
+ * Search the SAP table for the given SPANS SAP
+ */
+ for (i=0; i< MAX_SAP_ENT; i++) {
+ if (sap_table[i].spans_sap == ssap) {
+ *lsap = sap_table[i].local_sap;
+ return(TRUE);
+ }
+ }
+ return(FALSE);
+}
+#endif
+
+
+/*
+ * Allocate an ephemeral SPANS SAP
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance
+ *
+ * Returns:
+ * a SPANS ephemeral SAP number
+ *
+ */
+int
+spans_ephemeral_sap(spp)
+ struct spans *spp;
+{
+ return(SPANS_SAP_EPHEMERAL);
+}
+
+
+/*
+ * Translate an internal AAL designator to a SPANS AAL type
+ *
+ * Arguments:
+ * laal internal AAL designation
+ * saal a pointer to the variable to receive the SPANS AAL type
+ *
+ * Returns:
+ * TRUE the AAL was found; *saal is valid
+ * FALSE the AAL was not found; *saal is not valid
+ *
+ */
+int
+spans_get_spans_aal(laal, saal)
+ Aal_t laal;
+ spans_aal *saal;
+{
+ /*
+ *
+ */
+ switch (laal) {
+ case ATM_AAL0:
+ *saal = SPANS_AAL0;
+ return(TRUE);
+ case ATM_AAL1:
+ *saal = SPANS_AAL1;
+ return(TRUE);
+ case ATM_AAL2:
+ *saal = SPANS_AAL2;
+ return(TRUE);
+ case ATM_AAL3_4:
+ *saal = SPANS_AAL4;
+ return(TRUE);
+ case ATM_AAL5:
+ *saal = SPANS_AAL5;
+ return(TRUE);
+ default:
+ return(FALSE);
+ }
+}
+
+
+/*
+ * Translate a SPANS AAL type to an internal AAL designator
+ *
+ * Arguments:
+ * saal the SPANS AAL type
+ * laal a pointer to the variable to receive the internal
+ * AAL designation
+ *
+ * Returns:
+ * TRUE the AAL was found; *laal is valid
+ * FALSE the AAL was not found; *laal is not valid
+ *
+ */
+int
+spans_get_local_aal(saal, laal)
+ spans_aal saal;
+ Aal_t *laal;
+{
+ /*
+ *
+ */
+ switch (saal) {
+ case SPANS_AAL0:
+ *laal = ATM_AAL0;
+ return(TRUE);
+ case SPANS_AAL1:
+ *laal = ATM_AAL1;
+ return(TRUE);
+ case SPANS_AAL2:
+ *laal = ATM_AAL2;
+ return(TRUE);
+ case SPANS_AAL3:
+ case SPANS_AAL4:
+ *laal = ATM_AAL3_4;
+ return(TRUE);
+ case SPANS_AAL5:
+ *laal = ATM_AAL5;
+ return(TRUE);
+ default:
+ return(FALSE);
+ }
+}
+
+
+/*
+ * Verify a VCCB
+ *
+ * Search SPANS's VCCB queue to verify that a VCCB belongs to SPANS.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance
+ * svp pointer to a VCCB
+ *
+ * Returns:
+ * TRUE the VCCB belongs to SPANS
+ * FALSE the VCCB doesn't belong to SPANS
+ *
+ */
+int
+spans_verify_vccb(spp, svp)
+ struct spans *spp;
+ struct spans_vccb *svp;
+
+{
+ struct spans_vccb *vcp, *vcnext;
+
+ for (vcp = Q_HEAD(spp->sp_vccq, struct spans_vccb);
+ vcp; vcp = vcnext){
+ vcnext = Q_NEXT(vcp, struct spans_vccb, sv_sigelem);
+ if (svp == vcp) {
+ return(TRUE);
+ }
+ }
+ return(FALSE);
+}
+
+
+/*
+ * Find a VCCB
+ *
+ * Find a VCCB given the VPI and VCI.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance
+ * vpi the VPI to search for
+ * vci the VCI to search for
+ * dir the direction of the VCC (VCC_IN, VCC_OUT, or both).
+ * If dir is set to zero, return the address of any VCCB
+ * with the given VPI/VCI, regardless of direction.
+ *
+ * Returns:
+ * 0 there is no such VCCB
+ * address the address of the VCCB
+ *
+ */
+struct spans_vccb *
+spans_find_vpvc(spp, vpi, vci, dir)
+ struct spans *spp;
+ int vpi, vci;
+ u_char dir;
+
+{
+ struct spans_vccb *svp, *svnext;
+
+ for (svp = Q_HEAD(spp->sp_vccq, struct spans_vccb); svp;
+ svp = svnext){
+ svnext = Q_NEXT(svp, struct spans_vccb, sv_sigelem);
+ if (svp->sv_vpi == vpi &&
+ svp->sv_vci == vci &&
+ (svp->sv_type & dir) == dir)
+ break;
+ }
+ return(svp);
+}
+
+
+/*
+ * Find a connection
+ *
+ * Find a VCCB given the connection structure.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance
+ * p pointer to an spans_atm_conn structure
+ *
+ * Returns:
+ * 0 there is no such VCCB
+ * address the address of the VCCB
+ *
+ */
+struct spans_vccb *
+spans_find_conn(spp, p)
+ struct spans *spp;
+ struct spans_atm_conn *p;
+{
+ struct spans_vccb *svp, *svnext;
+
+ for (svp = Q_HEAD(spp->sp_vccq, struct spans_vccb); svp; svp = svnext){
+ svnext = Q_NEXT(svp, struct spans_vccb, sv_sigelem);
+ if (!bcmp(p, &svp->sv_conn, sizeof (spans_atm_conn)))
+ break;
+ }
+ return(svp);
+}
+
+
+/*
+ * Allocate a VPI/VCI pair
+ *
+ * When we get an open request or indication from the network, we have
+ * allocate a VPI and VCI for the conection. This routine will allocate
+ * a VPI/VCI based on the next available VCI in the SPANS protocol block.
+ * The VPI/VCI chose must be within the range allowed by the interface and
+ * must not already be in use.
+ *
+ * Currently the Fore ATM interface only supports VPI 0, so this code only
+ * allocates a VCI.
+ *
+ * There's probably a more elegant way to do this.
+ *
+ * Arguments:
+ * spp pointer to connection's SPANS protocol instance
+ *
+ * Returns:
+ * 0 no VPI/VCI available
+ * vpvc the VPI/VCI for the connection
+ *
+ */
+spans_vpvc
+spans_alloc_vpvc(spp)
+ struct spans *spp;
+{
+ int vpi, vci;
+
+ /*
+ * Loop through the allowable VCIs, starting with the curent one,
+ * to find one that's not in use.
+ */
+ while (spp->sp_alloc_vci <= spp->sp_max_vci) {
+ vpi = spp->sp_alloc_vpi;
+ vci = spp->sp_alloc_vci++;
+ if (!spans_find_vpvc(spp, vpi, vci, 0)) {
+ return(SPANS_PACK_VPIVCI(vpi, vci));
+ }
+ }
+
+ /*
+ * Reset the VCI to the minimum
+ */
+ spp->sp_alloc_vci = spp->sp_min_vci;
+
+ /*
+ * Try looping through again
+ */
+ while (spp->sp_alloc_vci <= spp->sp_max_vci) {
+ vpi = spp->sp_alloc_vpi;
+ vci = spp->sp_alloc_vci++;
+ if (!spans_find_vpvc(spp, vpi, vci, 0)) {
+ return(SPANS_PACK_VPIVCI(vpi, vci));
+ }
+ }
+
+ /*
+ * All allowable VCIs are in use
+ */
+ return(0);
+}
+
+
+/*
+ * Print a SPANS address
+ *
+ * Convert a SPANS address into an ASCII string suitable for printing.
+ *
+ * Arguments:
+ * p pointer to a struct spans_addr
+ *
+ * Returns:
+ * the address of a string with the ASCII representation of the
+ * address.
+ *
+ */
+char *
+spans_addr_print(p)
+ struct spans_addr *p;
+{
+ static char strbuff[80];
+ union {
+ int w;
+ char c[4];
+ } u1, u2;
+
+
+ /*
+ * Clear the returned string
+ */
+ KM_ZERO(strbuff, sizeof(strbuff));
+
+ /*
+ * Get address into integers
+ */
+ u1.c[0] =p->addr[0];
+ u1.c[1] =p->addr[1];
+ u1.c[2] =p->addr[2];
+ u1.c[3] =p->addr[3];
+ u2.c[0] =p->addr[4];
+ u2.c[1] =p->addr[5];
+ u2.c[2] =p->addr[6];
+ u2.c[3] =p->addr[7];
+
+ /*
+ * Print and return the string
+ */
+ sprintf(strbuff, "%x.%x", ntohl(u1.w), ntohl(u2.w));
+ return(strbuff);
+}
+
+
+/*
+ * Print a buffer chain
+ *
+ * Arguments:
+ * m pointer to a buffer chain
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+spans_dump_buffer(m)
+ KBuffer *m;
+{
+ int i;
+ caddr_t cp;
+
+ printf("spans_dump_buffer:\n");
+ while (m) {
+ KB_DATASTART(m, cp, caddr_t);
+ for (i = 0; i < KB_LEN(m); i++) {
+ if (i == 0)
+ printf(" bfr=0x%x: ", (int)m);
+ printf("%x ", (u_char)*cp++);
+ }
+ printf("<end_bfr>\n");
+ m = KB_NEXT(m);
+ }
+}
diff --git a/sys/netatm/spans/spans_var.h b/sys/netatm/spans/spans_var.h
new file mode 100644
index 0000000..8f9ac8a
--- /dev/null
+++ b/sys/netatm/spans/spans_var.h
@@ -0,0 +1,259 @@
+/*
+ *
+ * ===================================
+ * 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: spans_var.h,v 1.7 1998/04/09 14:24:18 johnc Exp $
+ *
+ */
+
+/*
+ * SPANS Signalling Manager
+ * ---------------------------
+ *
+ * Protocol control blocks
+ *
+ */
+
+#ifndef _SPANS_SPANS_VAR_H
+#define _SPANS_SPANS_VAR_H
+
+#ifdef ATM_KERNEL
+/*
+ * Constants to indicate the state of the signalling interface
+ */
+#define SPANS_UNI_UP 1
+#define SPANS_UNI_DOWN -1
+
+
+/*
+ * Structure containing state information for each SPANS protocol
+ * instance. There will be one instance for each ATM device interface
+ * using the SPANS signalling manager.
+ */
+struct spans {
+ struct siginst sp_inst; /* Header */
+ struct atm_time sp_time; /* Timer controls */
+ void (*sp_lower) /* Lower command handler */
+ __P((int, void *, int, int));
+ Atm_connection *sp_conn; /* Signalling connection */
+ long sp_s_epoch; /* Switch epoch */
+ long sp_h_epoch; /* Host epoch */
+ u_int sp_probe_ct; /* Status_req msgs unanswered */
+ u_int sp_alloc_vci; /* Next VCI to allocate */
+ u_int sp_alloc_vpi; /* Next VPI to allocate */
+ u_int sp_min_vci; /* Lowest VCI to allocate */
+ u_int sp_max_vci; /* Highest VCI to allocate */
+ struct spanscls *sp_cls; /* CLS instance */
+};
+
+#define sp_next sp_inst.si_next
+#define sp_pif sp_inst.si_pif
+#define sp_addr sp_inst.si_addr
+#define sp_subaddr sp_inst.si_subaddr
+#define sp_vccq sp_inst.si_vccq
+#define sp_state sp_inst.si_state
+#define sp_ipserv sp_inst.si_ipserv
+#endif /* ATM_KERNEL */
+
+/*
+ * SPANS Protocol States
+ */
+#define SPANS_ACTIVE 1 /* Active */
+#define SPANS_DETACH 2 /* Detach in progress */
+#define SPANS_INIT 3 /* Initializing */
+#define SPANS_PROBE 4 /* Exchanging status info */
+
+#define SPANS_PROBE_INTERVAL (ATM_HZ) /* Interval between SPANS_STAT_REQs */
+#define SPANS_PROBE_THRESH 10 /* Probe time-out threshold */
+#define SPANS_PROBE_ERR_WAIT (3 * ATM_HZ) /* Time to wait if send probe fails */
+
+
+#ifdef ATM_KERNEL
+/*
+ * SPANS Virtual Channel Connection control block. All information
+ * regarding the state of a SPANS-controlled VCC will be recorded here.
+ * There will be one SPANS VCC control block for each SPANS-controlled
+ * VCC.
+ */
+struct spans_vccb {
+ struct vccb vcp_hdr; /* Generic VCCB */
+ u_short sv_retry; /* Xmit retry count */
+ spans_atm_conn sv_conn; /* SPANS connection info */
+ spans_resrc sv_spans_qos; /* QoS for VCC */
+ spans_aal sv_spans_aal; /* AAL for VCC */
+};
+
+#define sv_type vcp_hdr.vc_type
+#define sv_proto vcp_hdr.vc_proto
+#define sv_sstate vcp_hdr.vc_sstate
+#define sv_ustate vcp_hdr.vc_ustate
+#define sv_pif vcp_hdr.vc_pif
+#define sv_nif vcp_hdr.vc_nif
+#define sv_sigelem vcp_hdr.vc_sigelem
+#define sv_time vcp_hdr.vc_time
+#define sv_vpi vcp_hdr.vc_vpi
+#define sv_vci vcp_hdr.vc_vci
+#define sv_connvc vcp_hdr.vc_connvc
+#define sv_ipdus vcp_hdr.vc_ipdus
+#define sv_opdus vcp_hdr.vc_opdus
+#define sv_ibytes vcp_hdr.vc_ibytes
+#define sv_obytes vcp_hdr.vc_obytes
+#define sv_ierrors vcp_hdr.vc_ierrors
+#define sv_oerrors vcp_hdr.vc_oerrors
+#define sv_tstamp vcp_hdr.vc_tstamp
+#define sv_daddr sv_conn.daddr
+#define sv_saddr sv_conn.saddr
+#define sv_dsap sv_conn.dsap
+#define sv_ssap sv_conn.ssap
+
+#define SV_MAX_RETRY 3
+#define SV_TIMEOUT (ATM_HZ)
+
+#endif /* ATM_KERNEL */
+
+
+/*
+ * SPANS VCC Signalling Protocol States
+ */
+#define SPANS_VC_NULL 0 /* No state */
+#define SPANS_VC_ACTIVE 1 /* Active */
+#define SPANS_VC_ACT_DOWN 2 /* Active - Interface down */
+#define SPANS_VC_POPEN 3 /* VCC open in progress */
+#define SPANS_VC_R_POPEN 4 /* VCC rmt open in progress */
+#define SPANS_VC_OPEN 5 /* VCC open */
+#define SPANS_VC_CLOSE 6 /* VCC close in progress */
+#define SPANS_VC_ABORT 7 /* VCC abort in progress */
+#define SPANS_VC_FREE 8 /* Waiting for user to free resources */
+
+
+#ifdef ATM_KERNEL
+/*
+ * Macro to compare two SPANS addresses.
+ *
+ * Returns 0 if the addresses are equal.
+ */
+#define spans_addr_cmp(a, b) \
+ (bcmp((caddr_t)a, (caddr_t)b, sizeof(struct spans_addr)))
+
+/*
+ * Macro to copy a SPANS address from a to b.
+ */
+#define spans_addr_copy(a, b) \
+ (KM_COPY((caddr_t)a, (caddr_t)b, sizeof(struct spans_addr)))
+
+
+/*
+ * Timer macros
+ */
+#define SPANS_TIMER(s, t) atm_timeout(&(s)->sp_time, (t), spans_timer)
+#define SPANS_CANCEL(s) atm_untimeout(&(s)->sp_time)
+#define SPANS_VC_TIMER(v, t) atm_timeout(&(v)->vc_time, (t), spans_vctimer)
+#define SPANS_VC_CANCEL(v) atm_untimeout(&(v)->vc_time)
+
+
+/*
+ * Global function declarations
+ */
+struct ipvcc;
+
+ /* spans_arp.c */
+int spansarp_svcout __P((struct ipvcc *, struct in_addr *));
+int spansarp_svcin __P((struct ipvcc *, Atm_addr *, Atm_addr *));
+int spansarp_svcactive __P((struct ipvcc *));
+void spansarp_vcclose __P((struct ipvcc *));
+void spansarp_ipact __P((struct spanscls *));
+void spansarp_ipdact __P((struct spanscls *));
+void spansarp_stop __P((void));
+void spansarp_input __P((struct spanscls *, KBuffer *));
+int spansarp_ioctl __P((int, caddr_t, caddr_t));
+
+ /* spans_cls.c */
+int spanscls_start __P((void));
+void spanscls_stop __P((void));
+int spanscls_attach __P((struct spans *));
+void spanscls_detach __P((struct spans *));
+void spanscls_closevc __P((struct spanscls *,
+ struct t_atm_cause *));
+
+ /* spans_if.c */
+int spans_abort __P((struct vccb *));
+int spans_free __P((struct vccb *));
+
+ /* spans_msg.c */
+int spans_send_msg __P((struct spans *, spans_msg *));
+int spans_send_open_req __P((struct spans *,
+ struct spans_vccb *));
+int spans_send_open_rsp __P((struct spans *,
+ struct spans_vccb *,
+ spans_result));
+int spans_send_close_req __P((struct spans *,
+ struct spans_vccb *));
+void spans_rcv_msg __P((struct spans *, KBuffer *));
+
+ /* spans_print.c */
+void spans_print_msg __P((spans_msg *));
+
+ /* spans_proto.c */
+void spans_timer __P((struct atm_time *));
+void spans_vctimer __P((struct atm_time *));
+void spans_upper __P((int, void *, int, int));
+void spans_notify __P((void *, int, int));
+
+ /* spans_subr.c */
+int spans_open_vcc __P((struct spans *, Atm_connvc *));
+int spans_close_vcc __P((struct spans *,
+ struct spans_vccb *, int));
+int spans_clear_vcc __P((struct spans *,
+ struct spans_vccb *));
+void spans_switch_reset __P((struct spans *, int));
+
+ /* spans_util.c */
+int spans_get_spans_sap __P((Sap_t, spans_sap *));
+int spans_get_local_sap __P((spans_sap, Sap_t *));
+int spans_ephemeral_sap __P((struct spans *));
+int spans_get_spans_aal __P((Aal_t, spans_aal *));
+int spans_get_local_aal __P((spans_aal, Aal_t *));
+int spans_verify_vccb __P((struct spans *,
+ struct spans_vccb *));
+struct spans_vccb *
+ spans_find_vpvc __P((struct spans *, int, int, u_char));
+struct spans_vccb *
+ spans_find_conn __P((struct spans *,
+ struct spans_atm_conn *));
+spans_vpvc spans_alloc_vpvc __P((struct spans *));
+char * spans_addr_print __P((struct spans_addr *));
+void spans_dump_buffer __P((KBuffer *));
+
+
+/*
+ * External variables
+ */
+extern struct spans_addr spans_bcastaddr;
+extern struct sp_info spans_vcpool;
+extern struct sp_info spans_msgpool;
+extern struct t_atm_cause spans_cause;
+
+#endif /* ATM_KERNEL */
+
+#endif /* _SPANS_SPANS_VAR_H */
diff --git a/sys/netatm/spans/spans_xdr.x b/sys/netatm/spans/spans_xdr.x
new file mode 100644
index 0000000..7e53f53
--- /dev/null
+++ b/sys/netatm/spans/spans_xdr.x
@@ -0,0 +1,513 @@
+%/*
+% *
+% * ===================================
+% * 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: spans_xdr.x,v 1.4 1997/05/06 22:17:36 mks Exp $
+% *
+% */
+%
+/*
+ * SPANS Signalling Manager
+ * ---------------------------
+ *
+ * SPANS Protocol Message XDR Specification
+ *
+ */
+
+#ifdef RPC_HDR
+%/*
+% * SPANS Signalling Manager
+% * ---------------------------
+% *
+% * SPANS Protocol Message Definitions
+% *
+% */
+%
+%#ifndef _SPANS_SPANS_XDR_H
+%#define _SPANS_SPANS_XDR_H
+%
+%#include <rpc/types.h>
+%
+#endif
+
+#ifdef RPC_XDR
+%/*
+% * SPANS Signalling Manager
+% * ---------------------------
+% *
+% * SPANS Protocol Message XDR Routines
+% *
+% */
+%
+%#ifndef lint
+%static char *RCSid = "@(#) $Id: spans_xdr.x,v 1.4 1997/05/06 22:17:36 mks Exp $";
+%#endif
+%
+#endif
+
+
+/*
+ * SPANS Signalling
+ */
+const SPANS_SIG_VPI = 0; /* Signalling VPI */
+const SPANS_SIG_VCI = 15; /* Signalling VCI */
+const SPANS_CLS_VPI = 0; /* Connectionless VPI */
+const SPANS_CLS_VCI = 14; /* Connectionless VCI */
+
+const SPANS_MIN_VCI = 32; /* Lowest VCI to allocate */
+const SPANS_MAX_VCI = 1023; /* Highest VCI to allocate */
+const SPANS_VPI = 0; /* Only VPI to allocate */
+
+/*
+ * SPANS Protocol Version
+ *
+ * Major_version * 256 + Minor_version
+ */
+typedef u_int spans_version;
+
+const SPANS_VERS_1_0 = 0x0100; /* Version 1.0 */
+
+
+/*
+ * VPI/VCI
+ *
+ * Format:
+ * 4 bits - unused
+ * 12 bits - VPI value
+ * 16 bits - VCI value
+ */
+typedef u_int spans_vpvc; /* VPI/VCI value */
+
+#ifdef RPC_HDR
+%#define SPANS_EXTRACT_VPI(p) (((p) >> 16) & 0x0FFF)
+%#define SPANS_EXTRACT_VCI(p) ((p) & 0x0FFFF)
+%#define SPANS_PACK_VPIVCI(p, c) ((((p) & 0x0FFF) << 16) | ((c) & 0x0FFFF))
+#endif
+
+
+/*
+ * VPI/VCI Preference
+ */
+struct spans_vpvc_pref {
+ bool vpf_valid; /* VPI/VCI values valid */
+ spans_vpvc vpf_vpvc; /* VPI/VCI value */
+};
+
+
+/*
+ * SPANS ATM Address
+ */
+struct spans_addr {
+ opaque addr[8]; /* SPANS ATM address */
+};
+
+
+/*
+ * Service Access Point (SAP)
+ */
+typedef u_int spans_sap; /* SAP value */
+
+const SPANS_SAP_IP = 1025; /* TCP/IP */
+const SPANS_SAP_EPHEMERAL = 2048; /* Start of ephemeral SAPs*/
+
+
+/*
+ * ATM Connection Identifier
+ */
+struct spans_atm_conn {
+ spans_addr con_dst; /* Destination ATM address */
+ spans_addr con_src; /* Source ATM address */
+ spans_sap con_dsap; /* Destination SAP */
+ spans_sap con_ssap; /* Source SAP */
+};
+
+
+/*
+ * Connection Resources
+ */
+struct spans_resrc {
+ u_int rsc_peak; /* Peak bandwidth (Kbps) */
+ u_int rsc_mean; /* Mean bandwidth (Kbps) */
+ u_int rsc_burst; /* Mean burst (Kb) */
+};
+
+
+/*
+ * ATM Adaptation Layer (AAL) Types
+ */
+enum spans_aal {
+ SPANS_AAL0 = 0, /* NULL AAL */
+ SPANS_AAL1 = 1, /* AAL 1 */
+ SPANS_AAL2 = 2, /* AAL 2 */
+ SPANS_AAL3 = 3, /* AAL 3 */
+ SPANS_AAL4 = 4, /* AAL 4 */
+ SPANS_AAL5 = 5 /* AAL 5 */
+};
+
+
+/*
+ * Result Codes
+ */
+enum spans_result {
+ SPANS_OK = 0, /* Success */
+ SPANS_FAIL = 1, /* Failure */
+ SPANS_NOVPVC = 2, /* No VP/VC */
+ SPANS_NORSC = 3, /* No resources */
+ SPANS_BADDEST = 4 /* Bad destination */
+};
+
+
+/*
+ * Message Types
+ */
+enum spans_msgtype {
+ /*
+ * SPANS UNI message types
+ */
+ SPANS_STAT_REQ = 0, /* Status request */
+ SPANS_STAT_IND = 1, /* Status indication */
+ SPANS_STAT_RSP = 2, /* Status response */
+ SPANS_OPEN_REQ = 3, /* Open request */
+ SPANS_OPEN_IND = 4, /* Open indication */
+ SPANS_OPEN_RSP = 5, /* Open response */
+ SPANS_OPEN_CNF = 6, /* Open confirmation */
+ SPANS_CLOSE_REQ = 7, /* Close request */
+ SPANS_CLOSE_IND = 8, /* Close indication */
+ SPANS_CLOSE_RSP = 9, /* Close response */
+ SPANS_CLOSE_CNF = 10, /* Close confirmation */
+ SPANS_RCLOSE_REQ = 11, /* Reverse close request */
+ SPANS_RCLOSE_IND = 12, /* Reverse close indication */
+ SPANS_RCLOSE_RSP = 13, /* Reverse close response */
+ SPANS_RCLOSE_CNF = 14, /* Reverse close confirmation */
+ SPANS_MULTI_REQ = 15, /* Multicast request */
+ SPANS_MULTI_IND = 16, /* Multicast indication */
+ SPANS_MULTI_RSP = 17, /* Multicast response */
+ SPANS_MULTI_CNF = 18, /* Multicast confirmation */
+ SPANS_ADD_REQ = 19, /* Add request */
+ SPANS_ADD_IND = 20, /* Add indication */
+ SPANS_ADD_RSP = 21, /* Add response */
+ SPANS_ADD_CNF = 22, /* Add confirmation */
+ SPANS_JOIN_REQ = 23, /* Join request */
+ SPANS_JOIN_CNF = 24, /* Join confirmation */
+ SPANS_LEAVE_REQ = 25, /* Leave request */
+ SPANS_LEAVE_CNF = 26, /* Leave confirmation */
+
+ /*
+ * SPANS NNI message types
+ */
+ SPANS_NSAP_IND = 99, /* NSAP routing message */
+ SPANS_MAP_IND = 100, /* Topology message */
+ SPANS_SETUP_REQ = 101, /* Setup request */
+ SPANS_SETUP_RSP = 102, /* Setup response */
+ SPANS_CHANGE_REQ = 103, /* Change request */
+ SPANS_CHANGE_RSP = 104, /* Change response */
+ SPANS_RELOC_REQ = 105, /* Relocation request */
+ SPANS_RELOC_RSP = 106, /* Relocation response */
+ SPANS_HELLO_IND = 107, /* Hello message */
+
+ SPANS_VCIR_IND = 108, /* VCI range indication */
+ SPANS_QUERY_REQ = 110, /* Conn. state query request */
+ SPANS_QUERY_RSP = 111 /* Conn. state query response */
+};
+
+
+/*
+ * Query types
+ */
+enum spans_query_type {
+ SPANS_QUERY_NORMAL, /* Normal--respond */
+ SPANS_QUERY_DEBUG, /* Debug--respond with state */
+ SPANS_QUERY_END_TO_END /* Not implemented */
+};
+
+
+/*
+ * SPANS connection states
+ */
+enum spans_conn_state {
+ SPANS_CONN_OPEN, /* Connection is open */
+ SPANS_CONN_OPEN_PEND, /* Connection is being opened */
+ SPANS_CONN_CLOSE_PEND, /* Connection is being closed */
+ SPANS_CONN_CLOSED /* Connection does not exist */
+};
+
+
+/*
+ * Message Parameters
+ *
+ * There is a separate message parameter structure for each
+ * message type.
+ */
+struct spans_parm_stat_req {
+ u_long streq_es_epoch; /* End system epoch */
+};
+
+struct spans_parm_stat_ind {
+ u_long stind_sw_epoch; /* Switch epoch */
+ spans_addr stind_es_addr; /* End system ATM address */
+ spans_addr stind_sw_addr; /* Switch ATM address */
+};
+
+struct spans_parm_stat_rsp {
+ u_long strsp_es_epoch; /* End system epoch */
+ spans_addr strsp_es_addr; /* End system ATM address */
+};
+
+struct spans_parm_open_req {
+ spans_atm_conn opreq_conn; /* Connection identity */
+ spans_aal opreq_aal; /* AAL type */
+ spans_resrc opreq_desrsrc; /* Desired resources */
+ spans_resrc opreq_minrsrc; /* Minimum resources */
+ spans_vpvc_pref opreq_vpvc; /* VPI/VCI preference */
+};
+
+struct spans_parm_open_ind {
+ spans_atm_conn opind_conn; /* Connection identity */
+ spans_aal opind_aal; /* AAL type */
+ spans_resrc opind_desrsrc; /* Desired resources */
+ spans_resrc opind_minrsrc; /* Minimum resources */
+ spans_vpvc_pref opind_vpvc; /* VPI/VCI preference */
+};
+
+struct spans_parm_open_rsp {
+ spans_atm_conn oprsp_conn; /* Connection identity */
+ spans_result oprsp_result; /* Open result */
+ spans_resrc oprsp_rsrc; /* Allocated resources */
+ spans_vpvc oprsp_vpvc; /* Allocated VPI/VCI */
+};
+
+struct spans_parm_open_cnf {
+ spans_atm_conn opcnf_conn; /* Connection identity */
+ spans_result opcnf_result; /* Open result */
+ spans_resrc opcnf_rsrc; /* Allocated resources */
+ spans_vpvc opcnf_vpvc; /* Allocated VPI/VCI */
+};
+
+struct spans_parm_close_req {
+ spans_atm_conn clreq_conn; /* Connection identity */
+};
+
+struct spans_parm_close_ind {
+ spans_atm_conn clind_conn; /* Connection identity */
+};
+
+struct spans_parm_close_rsp {
+ spans_atm_conn clrsp_conn; /* Connection identity */
+ spans_result clrsp_result; /* Close result */
+};
+
+struct spans_parm_close_cnf {
+ spans_atm_conn clcnf_conn; /* Connection identity */
+ spans_result clcnf_result; /* Close result */
+};
+
+struct spans_parm_rclose_req {
+ spans_atm_conn rcreq_conn; /* Connection identity */
+};
+
+struct spans_parm_rclose_ind {
+ spans_atm_conn rcind_conn; /* Connection identity */
+};
+
+struct spans_parm_rclose_rsp {
+ spans_atm_conn rcrsp_conn; /* Connection identity */
+ spans_result rcrsp_result; /* Rclose result */
+};
+
+struct spans_parm_rclose_cnf {
+ spans_atm_conn rccnf_conn; /* Connection identity */
+ spans_result rccnf_result; /* Rclose result */
+};
+
+struct spans_parm_multi_req {
+ spans_atm_conn mureq_conn; /* Connection identity */
+ spans_aal mureq_aal; /* AAL type */
+ spans_resrc mureq_desrsrc; /* Desired resources */
+ spans_resrc mureq_minrsrc; /* Minimum resources */
+ spans_vpvc mureq_vpvc; /* VPI/VCI preference */
+};
+
+struct spans_parm_multi_ind {
+ spans_atm_conn muind_conn; /* Connection identity */
+ spans_aal muind_aal; /* AAL type */
+ spans_resrc muind_desrsrc; /* Desired resources */
+ spans_resrc muind_minrsrc; /* Minimum resources */
+ spans_vpvc muind_vpvc; /* VPI/VCI preference */
+};
+
+struct spans_parm_multi_rsp {
+ spans_atm_conn mursp_conn; /* Connection identity */
+ spans_result mursp_result; /* Multi result */
+ spans_resrc mursp_rsrc; /* Allocated resources */
+ spans_vpvc mursp_vpvc; /* Allocated VPI/VCI */
+};
+
+struct spans_parm_multi_cnf {
+ spans_atm_conn mucnf_conn; /* Connection identity */
+ spans_result mucnf_result; /* Multi result */
+ spans_resrc mucnf_rsrc; /* Allocated resources */
+ spans_vpvc mucnf_vpvc; /* Allocated VPI/VCI */
+};
+
+struct spans_parm_add_req {
+ spans_atm_conn adreq_desconn; /* Desired connection identity */
+ spans_atm_conn adreq_xstconn; /* Existing connection identity */
+};
+
+struct spans_parm_add_ind {
+ spans_atm_conn adind_desconn; /* Desired connection identity */
+ spans_atm_conn adind_xstconn; /* Existing connection identity */
+};
+
+struct spans_parm_add_rsp {
+ spans_atm_conn adrsp_conn; /* Connection identity */
+ spans_result adrsp_result; /* Add result */
+ spans_resrc adrsp_rsrc; /* Allocated resources */
+};
+
+struct spans_parm_add_cnf {
+ spans_atm_conn adcnf_conn; /* Connection identity */
+ spans_result adcnf_result; /* Add result */
+ spans_resrc adcnf_rsrc; /* Allocated resources */
+};
+
+struct spans_parm_join_req {
+ spans_addr jnreq_addr; /* Group address */
+};
+
+struct spans_parm_join_cnf {
+ spans_addr jncnf_addr; /* Group address */
+ spans_result jncnf_result; /* Join result */
+};
+
+struct spans_parm_leave_req {
+ spans_addr lvreq_addr; /* Group address */
+};
+
+struct spans_parm_leave_cnf {
+ spans_addr lvcnf_addr; /* Group address */
+ spans_result lvcnf_result; /* Leave result */
+};
+
+struct spans_parm_vcir_ind {
+ u_int vrind_min; /* Lowest VCI available */
+ u_int vrind_max; /* Highest VCI available */
+};
+
+struct spans_parm_query_req {
+ spans_atm_conn qyreq_conn; /* Conn. being queried */
+ spans_query_type qyreq_type; /* Query type */
+};
+
+struct spans_parm_query_rsp {
+ spans_atm_conn qyrsp_conn; /* Conn. being queried */
+ spans_query_type qyrsp_type; /* Query type */
+ spans_conn_state qyrsp_state; /* Conn. state */
+ u_int qyrsp_data; /* Extra state data */
+};
+
+
+/*
+ * Message Body
+ */
+union spans_msgbody switch (spans_msgtype mb_type) {
+
+case SPANS_STAT_REQ: spans_parm_stat_req mb_stat_req;
+case SPANS_STAT_IND: spans_parm_stat_ind mb_stat_ind;
+case SPANS_STAT_RSP: spans_parm_stat_rsp mb_stat_rsp;
+case SPANS_OPEN_REQ: spans_parm_open_req mb_open_req;
+case SPANS_OPEN_IND: spans_parm_open_ind mb_open_ind;
+case SPANS_OPEN_RSP: spans_parm_open_rsp mb_open_rsp;
+case SPANS_OPEN_CNF: spans_parm_open_cnf mb_open_cnf;
+case SPANS_CLOSE_REQ: spans_parm_close_req mb_close_req;
+case SPANS_CLOSE_IND: spans_parm_close_ind mb_close_ind;
+case SPANS_CLOSE_RSP: spans_parm_close_rsp mb_close_rsp;
+case SPANS_CLOSE_CNF: spans_parm_close_cnf mb_close_cnf;
+case SPANS_RCLOSE_REQ: spans_parm_rclose_req mb_rclose_req;
+case SPANS_RCLOSE_IND: spans_parm_rclose_ind mb_rclose_ind;
+case SPANS_RCLOSE_RSP: spans_parm_rclose_rsp mb_rclose_rsp;
+case SPANS_RCLOSE_CNF: spans_parm_rclose_cnf mb_rclose_cnf;
+case SPANS_MULTI_REQ: spans_parm_multi_req mb_multi_req;
+case SPANS_MULTI_IND: spans_parm_multi_ind mb_multi_ind;
+case SPANS_MULTI_RSP: spans_parm_multi_rsp mb_multi_rsp;
+case SPANS_MULTI_CNF: spans_parm_multi_cnf mb_multi_cnf;
+case SPANS_ADD_REQ: spans_parm_add_req mb_add_req;
+case SPANS_ADD_IND: spans_parm_add_ind mb_add_ind;
+case SPANS_ADD_RSP: spans_parm_add_rsp mb_add_rsp;
+case SPANS_ADD_CNF: spans_parm_add_cnf mb_add_cnf;
+case SPANS_JOIN_REQ: spans_parm_join_req mb_join_req;
+case SPANS_JOIN_CNF: spans_parm_join_cnf mb_join_cnf;
+case SPANS_LEAVE_REQ: spans_parm_leave_req mb_leave_req;
+case SPANS_LEAVE_CNF: spans_parm_leave_cnf mb_leave_cnf;
+case SPANS_VCIR_IND: spans_parm_vcir_ind mb_vcir_ind;
+case SPANS_QUERY_REQ: spans_parm_query_req mb_query_req;
+case SPANS_QUERY_RSP: spans_parm_query_rsp mb_query_rsp;
+};
+
+
+/*
+ * Message Format
+ */
+struct spans_msg {
+ spans_version sm_vers;
+ spans_msgbody sm_body;
+};
+
+#ifdef RPC_HDR
+%#define sm_type sm_body.mb_type
+%#define sm_stat_req sm_body.spans_msgbody_u.mb_stat_req
+%#define sm_stat_ind sm_body.spans_msgbody_u.mb_stat_ind
+%#define sm_stat_rsp sm_body.spans_msgbody_u.mb_stat_rsp
+%#define sm_open_req sm_body.spans_msgbody_u.mb_open_req
+%#define sm_open_ind sm_body.spans_msgbody_u.mb_open_ind
+%#define sm_open_rsp sm_body.spans_msgbody_u.mb_open_rsp
+%#define sm_open_cnf sm_body.spans_msgbody_u.mb_open_cnf
+%#define sm_close_req sm_body.spans_msgbody_u.mb_close_req
+%#define sm_close_ind sm_body.spans_msgbody_u.mb_close_ind
+%#define sm_close_rsp sm_body.spans_msgbody_u.mb_close_rsp
+%#define sm_close_cnf sm_body.spans_msgbody_u.mb_close_cnf
+%#define sm_rclose_req sm_body.spans_msgbody_u.mb_rclose_req
+%#define sm_rclose_ind sm_body.spans_msgbody_u.mb_rclose_ind
+%#define sm_rclose_rsp sm_body.spans_msgbody_u.mb_rclose_rsp
+%#define sm_rclose_cnf sm_body.spans_msgbody_u.mb_rclose_cnf
+%#define sm_multi_req sm_body.spans_msgbody_u.mb_multi_req
+%#define sm_multi_ind sm_body.spans_msgbody_u.mb_multi_ind
+%#define sm_multi_rsp sm_body.spans_msgbody_u.mb_multi_rsp
+%#define sm_multi_cnf sm_body.spans_msgbody_u.mb_multi_cnf
+%#define sm_add_req sm_body.spans_msgbody_u.mb_add_req
+%#define sm_add_ind sm_body.spans_msgbody_u.mb_add_ind
+%#define sm_add_rsp sm_body.spans_msgbody_u.mb_add_rsp
+%#define sm_add_cnf sm_body.spans_msgbody_u.mb_add_cnf
+%#define sm_join_req sm_body.spans_msgbody_u.mb_join_req
+%#define sm_join_cnf sm_body.spans_msgbody_u.mb_join_cnf
+%#define sm_leave_req sm_body.spans_msgbody_u.mb_leave_req
+%#define sm_leave_cnf sm_body.spans_msgbody_u.mb_leave_cnf
+%#define sm_vcir_ind sm_body.spans_msgbody_u.mb_vcir_ind
+%#define sm_query_req sm_body.spans_msgbody_u.mb_query_req
+%#define sm_query_rsp sm_body.spans_msgbody_u.mb_query_rsp
+#endif
+
+#ifdef RPC_HDR
+%#endif /* _SPANS_SPANS_XDR_H */
+#endif
OpenPOWER on IntegriCloud