summaryrefslogtreecommitdiffstats
path: root/sys/netatm/uni
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/uni
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/uni')
-rw-r--r--sys/netatm/uni/Makefile93
-rw-r--r--sys/netatm/uni/q2110_sigaa.c516
-rw-r--r--sys/netatm/uni/q2110_sigcpcs.c1760
-rw-r--r--sys/netatm/uni/q2110_subr.c239
-rw-r--r--sys/netatm/uni/qsaal1_sigaa.c518
-rw-r--r--sys/netatm/uni/qsaal1_sigcpcs.c1545
-rw-r--r--sys/netatm/uni/qsaal1_subr.c206
-rw-r--r--sys/netatm/uni/sscf_uni.c317
-rw-r--r--sys/netatm/uni/sscf_uni.h47
-rw-r--r--sys/netatm/uni/sscf_uni_lower.c379
-rw-r--r--sys/netatm/uni/sscf_uni_upper.c625
-rw-r--r--sys/netatm/uni/sscf_uni_var.h115
-rw-r--r--sys/netatm/uni/sscop.c409
-rw-r--r--sys/netatm/uni/sscop.h80
-rw-r--r--sys/netatm/uni/sscop_lower.c349
-rw-r--r--sys/netatm/uni/sscop_misc.h97
-rw-r--r--sys/netatm/uni/sscop_pdu.c1237
-rw-r--r--sys/netatm/uni/sscop_pdu.h317
-rw-r--r--sys/netatm/uni/sscop_sigaa.c449
-rw-r--r--sys/netatm/uni/sscop_sigcpcs.c2311
-rw-r--r--sys/netatm/uni/sscop_subr.c972
-rw-r--r--sys/netatm/uni/sscop_timer.c576
-rw-r--r--sys/netatm/uni/sscop_upper.c412
-rw-r--r--sys/netatm/uni/sscop_var.h283
-rw-r--r--sys/netatm/uni/uni.h50
-rw-r--r--sys/netatm/uni/uni_load.c450
-rw-r--r--sys/netatm/uni/uniarp.c1231
-rw-r--r--sys/netatm/uni/uniarp_cache.c420
-rw-r--r--sys/netatm/uni/uniarp_input.c853
-rw-r--r--sys/netatm/uni/uniarp_output.c797
-rw-r--r--sys/netatm/uni/uniarp_timer.c320
-rw-r--r--sys/netatm/uni/uniarp_vcm.c708
-rw-r--r--sys/netatm/uni/uniip.c252
-rw-r--r--sys/netatm/uni/uniip_var.h318
-rw-r--r--sys/netatm/uni/unisig.h49
-rw-r--r--sys/netatm/uni/unisig_decode.c2474
-rw-r--r--sys/netatm/uni/unisig_decode.h87
-rw-r--r--sys/netatm/uni/unisig_encode.c1681
-rw-r--r--sys/netatm/uni/unisig_if.c1012
-rw-r--r--sys/netatm/uni/unisig_mbuf.c485
-rw-r--r--sys/netatm/uni/unisig_mbuf.h58
-rw-r--r--sys/netatm/uni/unisig_msg.c1002
-rw-r--r--sys/netatm/uni/unisig_msg.h953
-rw-r--r--sys/netatm/uni/unisig_print.c877
-rw-r--r--sys/netatm/uni/unisig_print.h47
-rw-r--r--sys/netatm/uni/unisig_proto.c324
-rw-r--r--sys/netatm/uni/unisig_sigmgr_state.c860
-rw-r--r--sys/netatm/uni/unisig_subr.c1276
-rw-r--r--sys/netatm/uni/unisig_util.c389
-rw-r--r--sys/netatm/uni/unisig_var.h321
-rw-r--r--sys/netatm/uni/unisig_vc_state.c2223
51 files changed, 33369 insertions, 0 deletions
diff --git a/sys/netatm/uni/Makefile b/sys/netatm/uni/Makefile
new file mode 100644
index 0000000..5b769b4
--- /dev/null
+++ b/sys/netatm/uni/Makefile
@@ -0,0 +1,93 @@
+#
+#
+# ===================================
+# HARP | Host ATM Research Platform
+# ===================================
+#
+#
+# This Host ATM Research Platform ("HARP") file (the "Software") is
+# made available by Network Computing Services, Inc. ("NetworkCS")
+# "AS IS". NetworkCS does not provide maintenance, improvements or
+# support of any kind.
+#
+# NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+# INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+# SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+# In no event shall NetworkCS be responsible for any damages, including
+# but not limited to consequential damages, arising from or relating to
+# any use of the Software or related support.
+#
+# Copyright 1994-1998 Network Computing Services, Inc.
+#
+# Copies of this Software may be made, however, the above copyright
+# notice must be reproduced on all copies.
+#
+# @(#) $Id: Makefile,v 1.6 1998/08/26 23:29:17 mks Exp $
+#
+#
+
+#
+# ATM Forum UNI Support
+# ---------------------
+#
+# Source directory Makefile
+#
+#
+
+DEFS=
+
+UNI_HDRS= uni.h
+UNI_SRCS= uni_load.c
+UNI_OBJS= uni_load.o
+
+SIG_HDRS= unisig.h unisig_decode.h unisig_mbuf.h \
+ unisig_msg.h unisig_print.h unisig_var.h
+SIG_SRCS= unisig_decode.c unisig_encode.c unisig_if.c \
+ unisig_mbuf.c unisig_msg.c \
+ unisig_print.c unisig_proto.c \
+ unisig_sigmgr_state.c unisig_subr.c \
+ unisig_util.c unisig_vc_state.c
+SIG_OBJS= unisig_decode.o unisig_encode.o unisig_if.o \
+ unisig_mbuf.o unisig_msg.o \
+ unisig_print.o unisig_proto.o \
+ unisig_sigmgr_state.o unisig_subr.o \
+ unisig_util.o unisig_vc_state.o
+
+SAAL_HDRS= sscop.h sscop_misc.h sscop_pdu.h sscop_var.h \
+ sscf_uni.h sscf_uni_var.h
+SAAL_SRCS= sscop.c sscop_lower.c sscop_pdu.c sscop_sigaa.c \
+ sscop_sigcpcs.c sscop_subr.c sscop_timer.c sscop_upper.c \
+ qsaal1_sigaa.c qsaal1_sigcpcs.c qsaal1_subr.c \
+ q2110_sigaa.c q2110_sigcpcs.c q2110_subr.c \
+ sscf_uni.c sscf_uni_lower.c sscf_uni_upper.c
+SAAL_OBJS= sscop.o sscop_lower.o sscop_pdu.o sscop_sigaa.o \
+ sscop_sigcpcs.o sscop_subr.o sscop_timer.o sscop_upper.o \
+ qsaal1_sigaa.o qsaal1_sigcpcs.o qsaal1_subr.o \
+ q2110_sigaa.o q2110_sigcpcs.o q2110_subr.o \
+ sscf_uni.o sscf_uni_lower.o sscf_uni_upper.o
+
+IP_HDRS= uniip_var.h
+IP_SRCS= uniip.c uniarp.c uniarp_cache.c uniarp_input.c \
+ uniarp_output.c uniarp_timer.c uniarp_vcm.c
+IP_OBJS= uniip.o uniarp.o uniarp_cache.o uniarp_input.o \
+ uniarp_output.o uniarp_timer.o uniarp_vcm.o
+
+HDRS= $(UNI_HDRS) $(SIG_HDRS) $(SAAL_HDRS) $(IP_HDRS)
+SRCS= $(UNI_SRCS) $(SIG_SRCS) $(SAAL_SRCS) $(IP_SRCS)
+OBJS= $(UNI_OBJS) $(SIG_OBJS) $(SAAL_OBJS) $(IP_OBJS)
+MOD= uni_mod.o
+
+OBJDIR= ../../`../../config/mkobjname -d`/uni
+
+all $(OBJS) $(MOD) config install clean depend lint load unload:
+ @if [ -d $(OBJDIR) ]; then \
+ echo "cd $(OBJDIR); $(MAKE) $@"; \
+ cd $(OBJDIR); \
+ $(MAKE) $(MFLAGS) DEFS='$(DEFS)' HDRS='$(HDRS)' SRCS='$(SRCS)' OBJS='$(OBJS)' $@; \
+ exit $$?; \
+ else \
+ echo "Object directory \"$(OBJDIR)\" does not exist."; \
+ exit 1; \
+ fi
+
diff --git a/sys/netatm/uni/q2110_sigaa.c b/sys/netatm/uni/q2110_sigaa.c
new file mode 100644
index 0000000..357df71
--- /dev/null
+++ b/sys/netatm/uni/q2110_sigaa.c
@@ -0,0 +1,516 @@
+/*
+ *
+ * ===================================
+ * 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: q2110_sigaa.c,v 1.6 1998/08/26 23:29:18 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * ITU-T Q.2110 - Process AA-signals (SAP_SSCOP)
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: q2110_sigaa.c,v 1.6 1998/08/26 23:29:18 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/uni.h>
+#include <netatm/uni/sscop.h>
+#include <netatm/uni/sscop_misc.h>
+#include <netatm/uni/sscop_pdu.h>
+#include <netatm/uni/sscop_var.h>
+
+
+/*
+ * Local functions
+ */
+static void sscop_resreq_ready __P((struct sscop *, int, int));
+static void sscop_resrsp_inresyn __P((struct sscop *, int, int));
+static void sscop_recrsp_recovrsp __P((struct sscop *, int, int));
+static void sscop_recrsp_inrecov __P((struct sscop *, int, int));
+
+
+/*
+ * Stack command state lookup tables
+ */
+/* SSCOP_INIT */
+static void (*sscop_init_tab[SOS_NUMSTATES])
+ __P((struct sscop *, int, int)) = {
+ sscop_init_inst, /* SOS_INST */
+ NULL, /* SOS_IDLE */
+ NULL, /* SOS_OUTCONN */
+ NULL, /* SOS_INCONN */
+ NULL, /* SOS_OUTDISC */
+ NULL, /* SOS_OUTRESYN */
+ NULL, /* SOS_INRESYN */
+ NULL, /* SOS_OUTRECOV */
+ NULL, /* SOS_RECOVRSP */
+ NULL, /* SOS_INRECOV */
+ NULL, /* SOS_READY */
+ NULL /* SOS_TERM */
+};
+
+/* SSCOP_TERM */
+static void (*sscop_term_tab[SOS_NUMSTATES])
+ __P((struct sscop *, int, int)) = {
+ sscop_term_all, /* SOS_INST */
+ sscop_term_all, /* SOS_IDLE */
+ sscop_term_all, /* SOS_OUTCONN */
+ sscop_term_all, /* SOS_INCONN */
+ sscop_term_all, /* SOS_OUTDISC */
+ sscop_term_all, /* SOS_OUTRESYN */
+ sscop_term_all, /* SOS_INRESYN */
+ sscop_term_all, /* SOS_OUTRECOV */
+ sscop_term_all, /* SOS_RECOVRSP */
+ sscop_term_all, /* SOS_INRECOV */
+ sscop_term_all, /* SOS_READY */
+ sscop_term_all /* SOS_TERM */
+};
+
+/* SSCOP_ESTABLISH_REQ */
+static void (*sscop_estreq_tab[SOS_NUMSTATES])
+ __P((struct sscop *, int, int)) = {
+ NULL, /* SOS_INST */
+ sscop_estreq_idle, /* SOS_IDLE */
+ NULL, /* SOS_OUTCONN */
+ NULL, /* SOS_INCONN */
+ sscop_estreq_idle, /* SOS_OUTDISC */
+ NULL, /* SOS_OUTRESYN */
+ NULL, /* SOS_INRESYN */
+ NULL, /* SOS_OUTRECOV */
+ NULL, /* SOS_RECOVRSP */
+ NULL, /* SOS_INRECOV */
+ NULL, /* SOS_READY */
+ sscop_aa_noop_1 /* SOS_TERM */
+};
+
+/* SSCOP_ESTABLISH_RSP */
+static void (*sscop_estrsp_tab[SOS_NUMSTATES])
+ __P((struct sscop *, int, int)) = {
+ NULL, /* SOS_INST */
+ NULL, /* SOS_IDLE */
+ NULL, /* SOS_OUTCONN */
+ sscop_estrsp_inconn, /* SOS_INCONN */
+ NULL, /* SOS_OUTDISC */
+ NULL, /* SOS_OUTRESYN */
+ NULL, /* SOS_INRESYN */
+ NULL, /* SOS_OUTRECOV */
+ NULL, /* SOS_RECOVRSP */
+ NULL, /* SOS_INRECOV */
+ NULL, /* SOS_READY */
+ sscop_aa_noop_1 /* SOS_TERM */
+};
+
+/* SSCOP_RELEASE_REQ */
+static void (*sscop_relreq_tab[SOS_NUMSTATES])
+ __P((struct sscop *, int, int)) = {
+ NULL, /* SOS_INST */
+ NULL, /* SOS_IDLE */
+ sscop_relreq_outconn, /* SOS_OUTCONN */
+ sscop_relreq_inconn, /* SOS_INCONN */
+ NULL, /* SOS_OUTDISC */
+ sscop_relreq_outconn, /* SOS_OUTRESYN */
+ sscop_relreq_outconn, /* SOS_INRESYN */
+ sscop_relreq_ready, /* SOS_OUTRECOV */
+ sscop_relreq_outconn, /* SOS_RECOVRSP */
+ sscop_relreq_outconn, /* SOS_INRECOV */
+ sscop_relreq_ready, /* SOS_READY */
+ sscop_aa_noop_1 /* SOS_TERM */
+};
+
+/* SSCOP_DATA_REQ */
+static void (*sscop_datreq_tab[SOS_NUMSTATES])
+ __P((struct sscop *, int, int)) = {
+ NULL, /* SOS_INST */
+ NULL, /* SOS_IDLE */
+ NULL, /* SOS_OUTCONN */
+ NULL, /* SOS_INCONN */
+ NULL, /* SOS_OUTDISC */
+ NULL, /* SOS_OUTRESYN */
+ NULL, /* SOS_INRESYN */
+ sscop_aa_noop_1, /* SOS_OUTRECOV */
+ NULL, /* SOS_RECOVRSP */
+ NULL, /* SOS_INRECOV */
+ sscop_datreq_ready, /* SOS_READY */
+ sscop_aa_noop_1 /* SOS_TERM */
+};
+
+/* SSCOP_RESYNC_REQ */
+static void (*sscop_resreq_tab[SOS_NUMSTATES])
+ __P((struct sscop *, int, int)) = {
+ NULL, /* SOS_INST */
+ NULL, /* SOS_IDLE */
+ NULL, /* SOS_OUTCONN */
+ NULL, /* SOS_INCONN */
+ NULL, /* SOS_OUTDISC */
+ NULL, /* SOS_OUTRESYN */
+ NULL, /* SOS_INRESYN */
+ sscop_resreq_ready, /* SOS_OUTRECOV */
+ sscop_resreq_ready, /* SOS_RECOVRSP */
+ sscop_resreq_ready, /* SOS_INRECOV */
+ sscop_resreq_ready, /* SOS_READY */
+ sscop_aa_noop_1 /* SOS_TERM */
+};
+
+/* SSCOP_RESYNC_RSP */
+static void (*sscop_resrsp_tab[SOS_NUMSTATES])
+ __P((struct sscop *, int, int)) = {
+ NULL, /* SOS_INST */
+ NULL, /* SOS_IDLE */
+ NULL, /* SOS_OUTCONN */
+ NULL, /* SOS_INCONN */
+ NULL, /* SOS_OUTDISC */
+ NULL, /* SOS_OUTRESYN */
+ sscop_resrsp_inresyn, /* SOS_INRESYN */
+ NULL, /* SOS_OUTRECOV */
+ NULL, /* SOS_RECOVRSP */
+ NULL, /* SOS_INRECOV */
+ NULL, /* SOS_READY */
+ sscop_aa_noop_0 /* SOS_TERM */
+};
+
+/* SSCOP_RECOVER_RSP */
+static void (*sscop_recrsp_tab[SOS_NUMSTATES])
+ __P((struct sscop *, int, int)) = {
+ NULL, /* SOS_INST */
+ NULL, /* SOS_IDLE */
+ NULL, /* SOS_OUTCONN */
+ NULL, /* SOS_INCONN */
+ NULL, /* SOS_OUTDISC */
+ NULL, /* SOS_OUTRESYN */
+ NULL, /* SOS_INRESYN */
+ NULL, /* SOS_OUTRECOV */
+ sscop_recrsp_recovrsp, /* SOS_RECOVRSP */
+ sscop_recrsp_inrecov, /* SOS_INRECOV */
+ NULL, /* SOS_READY */
+ sscop_aa_noop_0 /* SOS_TERM */
+};
+
+/* SSCOP_UNITDATA_REQ */
+static void (*sscop_udtreq_tab[SOS_NUMSTATES])
+ __P((struct sscop *, int, int)) = {
+ NULL, /* SOS_INST */
+ sscop_udtreq_all, /* SOS_IDLE */
+ sscop_udtreq_all, /* SOS_OUTCONN */
+ sscop_udtreq_all, /* SOS_INCONN */
+ sscop_udtreq_all, /* SOS_OUTDISC */
+ sscop_udtreq_all, /* SOS_OUTRESYN */
+ sscop_udtreq_all, /* SOS_INRESYN */
+ sscop_udtreq_all, /* SOS_OUTRECOV */
+ sscop_udtreq_all, /* SOS_RECOVRSP */
+ sscop_udtreq_all, /* SOS_INRECOV */
+ sscop_udtreq_all, /* SOS_READY */
+ sscop_aa_noop_1 /* SOS_TERM */
+};
+
+/* SSCOP_RETRIEVE_REQ */
+static void (*sscop_retreq_tab[SOS_NUMSTATES])
+ __P((struct sscop *, int, int)) = {
+ NULL, /* SOS_INST */
+ NULL, /* SOS_IDLE */
+ NULL, /* SOS_OUTCONN */
+ NULL, /* SOS_INCONN */
+ NULL, /* SOS_OUTDISC */
+ NULL, /* SOS_OUTRESYN */
+ NULL, /* SOS_INRESYN */
+ NULL, /* SOS_OUTRECOV */
+ NULL, /* SOS_RECOVRSP */
+ NULL, /* SOS_INRECOV */
+ NULL, /* SOS_READY */
+ NULL /* SOS_TERM */
+};
+
+
+/*
+ * Stack command lookup table
+ */
+void (*(*sscop_q2110_aatab[SSCOP_CMD_SIZE]))
+ __P((struct sscop *, int, int)) = {
+ NULL,
+ sscop_init_tab,
+ sscop_term_tab,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ sscop_estreq_tab,
+ NULL,
+ sscop_estrsp_tab,
+ NULL,
+ sscop_relreq_tab,
+ NULL,
+ NULL,
+ sscop_datreq_tab,
+ NULL,
+ sscop_resreq_tab,
+ NULL,
+ sscop_resrsp_tab,
+ NULL,
+ NULL,
+ sscop_recrsp_tab,
+ sscop_udtreq_tab,
+ NULL,
+ sscop_retreq_tab,
+ NULL,
+ NULL
+};
+
+
+/*
+ * SSCOP_RESYNC_REQ / SOS_READY Command Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * arg1 pointer to buffer containing SSCOP-UU data
+ * arg2 unused
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_resreq_ready(sop, arg1, arg2)
+ struct sscop *sop;
+ int arg1;
+ int arg2;
+{
+
+ /*
+ * We don't support SSCOP-UU data
+ */
+ if (arg1 != SSCOP_UU_NULL)
+ KB_FREEALL((KBuffer *)arg1);
+
+ /*
+ * Stop data transfer timers
+ */
+ sop->so_timer[SSCOP_T_POLL] = 0;
+ sop->so_timer[SSCOP_T_NORESP] = 0;
+ sop->so_timer[SSCOP_T_IDLE] = 0;
+ sop->so_flags &= ~SOF_KEEPALIVE;
+
+ /*
+ * Initialize receiver window
+ */
+ SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin);
+
+ /*
+ * Send first RS PDU
+ */
+ sop->so_connctl = 1;
+ SEQ_INCR(sop->so_sendconn, 1);
+ (void) sscop_send_rs(sop);
+
+ /*
+ * Drain transmit and receive queues
+ */
+ sscop_xmit_drain(sop);
+ sscop_rcvr_drain(sop);
+
+ /*
+ * Set retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc;
+
+ /*
+ * Wait for RSAK
+ */
+ sop->so_state = SOS_OUTRESYN;
+
+ return;
+}
+
+
+/*
+ * SSCOP_RESYNC_RSP / SOS_INRESYN Command Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * arg1 unused
+ * arg2 unused
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_resrsp_inresyn(sop, arg1, arg2)
+ struct sscop *sop;
+ int arg1;
+ int arg2;
+{
+
+ /*
+ * Clear transmitter buffers
+ */
+ q2110_clear_xmit(sop);
+
+ /*
+ * Initialize state variables
+ */
+ SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin);
+ q2110_init_state(sop);
+
+ /*
+ * Send RSAK PDU
+ */
+ (void) sscop_send_rsak(sop);
+
+ /*
+ * Start data transfer timers
+ */
+ sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll;
+ sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
+
+ /*
+ * Back to data transfer state
+ */
+ sop->so_state = SOS_READY;
+
+ return;
+}
+
+
+/*
+ * SSCOP_RECOVER_RSP / SOS_RECOVRSP Command Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * arg1 unused
+ * arg2 unused
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_recrsp_recovrsp(sop, arg1, arg2)
+ struct sscop *sop;
+ int arg1;
+ int arg2;
+{
+
+ /*
+ * Clear transmitter buffers, if not done earlier
+ */
+ if (sop->so_flags & SOF_NOCLRBUF)
+ q2110_clear_xmit(sop);
+
+ /*
+ * Initialize state variables
+ */
+ q2110_init_state(sop);
+
+ /*
+ * Start data transfer timers
+ */
+ sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll;
+ sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
+
+ /*
+ * Back to data transfer state
+ */
+ sop->so_state = SOS_READY;
+
+ /*
+ * See if transmit queues need servicing
+ */
+ if (sop->so_flags & SOF_XMITSRVC)
+ sscop_service_xmit(sop);
+
+ return;
+}
+
+
+/*
+ * SSCOP_RECOVER_RSP / SOS_INRECOV Command Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * arg1 unused
+ * arg2 unused
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_recrsp_inrecov(sop, arg1, arg2)
+ struct sscop *sop;
+ int arg1;
+ int arg2;
+{
+
+ /*
+ * Clear transmitter buffers, if not done earlier
+ */
+ if (sop->so_flags & SOF_NOCLRBUF)
+ q2110_clear_xmit(sop);
+
+ /*
+ * Initialize state variables
+ */
+ SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin);
+ q2110_init_state(sop);
+
+ /*
+ * Send ERAK PDU
+ */
+ (void) sscop_send_erak(sop);
+
+ /*
+ * Start data transfer timers
+ */
+ sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll;
+ sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
+
+ /*
+ * Back to data transfer state
+ */
+ sop->so_state = SOS_READY;
+
+ /*
+ * See if transmit queues need servicing
+ */
+ if (sop->so_flags & SOF_XMITSRVC)
+ sscop_service_xmit(sop);
+
+ return;
+}
+
diff --git a/sys/netatm/uni/q2110_sigcpcs.c b/sys/netatm/uni/q2110_sigcpcs.c
new file mode 100644
index 0000000..0fa5555
--- /dev/null
+++ b/sys/netatm/uni/q2110_sigcpcs.c
@@ -0,0 +1,1760 @@
+/*
+ *
+ * ===================================
+ * 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: q2110_sigcpcs.c,v 1.7 1998/08/26 23:29:18 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * ITU-T Q.2110 - Process CPCS-signals (SSCOP PDUs)
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: q2110_sigcpcs.c,v 1.7 1998/08/26 23:29:18 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/uni.h>
+#include <netatm/uni/sscop.h>
+#include <netatm/uni/sscop_misc.h>
+#include <netatm/uni/sscop_pdu.h>
+#include <netatm/uni/sscop_var.h>
+
+
+/*
+ * Local functions
+ */
+static void sscop_bgn_outconn __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_bgn_inconn __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_bgn_ready __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_bgrej_outrecov __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_end_outrecov __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_end_ready __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_endak_outrecov __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_rs_outresyn __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_rs_inresyn __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_rs_outrecov __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_rs_ready __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_er_error __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_er_idle __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_er_outrecov __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_er_recovrsp __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_er_inrecov __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_er_ready __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_erak_error __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_erak_idle __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_erak_outrecov __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_sd_ready __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_poll_ready __P((struct sscop *, KBuffer *, caddr_t));
+
+
+/*
+ * PDU type state lookup tables
+ */
+/* BGN PDU */
+static void (*sscop_bgn_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_bgn_idle, /* SOS_IDLE */
+ sscop_bgn_outconn, /* SOS_OUTCONN */
+ sscop_bgn_inconn, /* SOS_INCONN */
+ sscop_bgn_outdisc, /* SOS_OUTDISC */
+ sscop_bgn_outresyn, /* SOS_OUTRESYN */
+ sscop_bgn_inresyn, /* SOS_INRESYN */
+ sscop_bgn_inresyn, /* SOS_OUTRECOV */
+ sscop_bgn_inresyn, /* SOS_RECOVRSP */
+ sscop_bgn_inresyn, /* SOS_INRECOV */
+ sscop_bgn_ready, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+/* BGAK PDU */
+static void (*sscop_bgak_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_bgak_idle, /* SOS_IDLE */
+ sscop_bgak_outconn, /* SOS_OUTCONN */
+ sscop_bgak_error, /* SOS_INCONN */
+ sscop_noop, /* SOS_OUTDISC */
+ sscop_noop, /* SOS_OUTRESYN */
+ sscop_bgak_error, /* SOS_INRESYN */
+ sscop_bgak_error, /* SOS_OUTRECOV */
+ sscop_bgak_error, /* SOS_RECOVRSP */
+ sscop_bgak_error, /* SOS_INRECOV */
+ sscop_noop, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+/* BGREJ PDU */
+static void (*sscop_bgrej_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_bgrej_error, /* SOS_IDLE */
+ sscop_bgrej_outconn, /* SOS_OUTCONN */
+ sscop_bgrej_inconn, /* SOS_INCONN */
+ sscop_endak_outdisc, /* SOS_OUTDISC */
+ sscop_bgrej_outresyn, /* SOS_OUTRESYN */
+ sscop_bgrej_inconn, /* SOS_INRESYN */
+ sscop_bgrej_outrecov, /* SOS_OUTRECOV */
+ sscop_bgrej_inconn, /* SOS_RECOVRSP */
+ sscop_bgrej_inconn, /* SOS_INRECOV */
+ sscop_bgrej_ready, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+/* END PDU */
+static void (*sscop_end_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_end_idle, /* SOS_IDLE */
+ sscop_noop, /* SOS_OUTCONN */
+ sscop_end_inconn, /* SOS_INCONN */
+ sscop_end_outdisc, /* SOS_OUTDISC */
+ sscop_end_inconn, /* SOS_OUTRESYN */
+ sscop_end_inconn, /* SOS_INRESYN */
+ sscop_end_outrecov, /* SOS_OUTRECOV */
+ sscop_end_inconn, /* SOS_RECOVRSP */
+ sscop_end_inconn, /* SOS_INRECOV */
+ sscop_end_ready, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+/* ENDAK PDU */
+static void (*sscop_endak_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_noop, /* SOS_IDLE */
+ sscop_noop, /* SOS_OUTCONN */
+ sscop_endak_inconn, /* SOS_INCONN */
+ sscop_endak_outdisc, /* SOS_OUTDISC */
+ sscop_endak_inconn, /* SOS_OUTRESYN */
+ sscop_endak_inconn, /* SOS_INRESYN */
+ sscop_endak_outrecov, /* SOS_OUTRECOV */
+ sscop_endak_inconn, /* SOS_RECOVRSP */
+ sscop_endak_inconn, /* SOS_INRECOV */
+ sscop_endak_ready, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+/* RS PDU */
+static void (*sscop_rs_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_rs_idle, /* SOS_IDLE */
+ sscop_noop, /* SOS_OUTCONN */
+ sscop_rs_error, /* SOS_INCONN */
+ sscop_noop, /* SOS_OUTDISC */
+ sscop_rs_outresyn, /* SOS_OUTRESYN */
+ sscop_rs_inresyn, /* SOS_INRESYN */
+ sscop_rs_outrecov, /* SOS_OUTRECOV */
+ sscop_rs_outrecov, /* SOS_RECOVRSP */
+ sscop_rs_outrecov, /* SOS_INRECOV */
+ sscop_rs_ready, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+/* RSAK PDU */
+static void (*sscop_rsak_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_rsak_idle, /* SOS_IDLE */
+ sscop_noop, /* SOS_OUTCONN */
+ sscop_rsak_error, /* SOS_INCONN */
+ sscop_noop, /* SOS_OUTDISC */
+ sscop_rsak_outresyn, /* SOS_OUTRESYN */
+ sscop_rsak_error, /* SOS_INRESYN */
+ sscop_rsak_error, /* SOS_OUTRECOV */
+ sscop_rsak_error, /* SOS_RECOVRSP */
+ sscop_rsak_error, /* SOS_INRECOV */
+ sscop_noop, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+/* ER PDU */
+static void (*sscop_er_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_er_idle, /* SOS_IDLE */
+ sscop_noop, /* SOS_OUTCONN */
+ sscop_er_error, /* SOS_INCONN */
+ sscop_noop, /* SOS_OUTDISC */
+ sscop_noop, /* SOS_OUTRESYN */
+ sscop_er_error, /* SOS_INRESYN */
+ sscop_er_outrecov, /* SOS_OUTRECOV */
+ sscop_er_recovrsp, /* SOS_RECOVRSP */
+ sscop_er_inrecov, /* SOS_INRECOV */
+ sscop_er_ready, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+/* ERAK PDU */
+static void (*sscop_erak_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_erak_idle, /* SOS_IDLE */
+ sscop_noop, /* SOS_OUTCONN */
+ sscop_erak_error, /* SOS_INCONN */
+ sscop_noop, /* SOS_OUTDISC */
+ sscop_noop, /* SOS_OUTRESYN */
+ sscop_erak_error, /* SOS_INRESYN */
+ sscop_erak_outrecov, /* SOS_OUTRECOV */
+ sscop_noop, /* SOS_RECOVRSP */
+ sscop_erak_error, /* SOS_INRECOV */
+ sscop_noop, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+/* SD PDU */
+static void (*sscop_sd_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_sd_idle, /* SOS_IDLE */
+ sscop_noop, /* SOS_OUTCONN */
+ sscop_sd_inconn, /* SOS_INCONN */
+ sscop_noop, /* SOS_OUTDISC */
+ sscop_noop, /* SOS_OUTRESYN */
+ sscop_sd_inconn, /* SOS_INRESYN */
+ sscop_noop, /* SOS_OUTRECOV */
+ sscop_noop, /* SOS_RECOVRSP */
+ sscop_sd_inconn, /* SOS_INRECOV */
+ sscop_sd_ready, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+/* POLL PDU */
+static void (*sscop_poll_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_poll_idle, /* SOS_IDLE */
+ sscop_noop, /* SOS_OUTCONN */
+ sscop_poll_inconn, /* SOS_INCONN */
+ sscop_noop, /* SOS_OUTDISC */
+ sscop_noop, /* SOS_OUTRESYN */
+ sscop_poll_inconn, /* SOS_INRESYN */
+ sscop_noop, /* SOS_OUTRECOV */
+ sscop_noop, /* SOS_RECOVRSP */
+ sscop_poll_inconn, /* SOS_INRECOV */
+ sscop_poll_ready, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+/* STAT PDU */
+static void (*sscop_stat_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_stat_idle, /* SOS_IDLE */
+ sscop_noop, /* SOS_OUTCONN */
+ sscop_stat_inconn, /* SOS_INCONN */
+ sscop_noop, /* SOS_OUTDISC */
+ sscop_noop, /* SOS_OUTRESYN */
+ sscop_stat_inconn, /* SOS_INRESYN */
+ sscop_noop, /* SOS_OUTRECOV */
+ sscop_stat_inconn, /* SOS_RECOVRSP */
+ sscop_stat_inconn, /* SOS_INRECOV */
+ sscop_stat_ready, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+/* USTAT PDU */
+static void (*sscop_ustat_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_ustat_idle, /* SOS_IDLE */
+ sscop_noop, /* SOS_OUTCONN */
+ sscop_ustat_inconn, /* SOS_INCONN */
+ sscop_noop, /* SOS_OUTDISC */
+ sscop_noop, /* SOS_OUTRESYN */
+ sscop_ustat_inconn, /* SOS_INRESYN */
+ sscop_noop, /* SOS_OUTRECOV */
+ sscop_ustat_inconn, /* SOS_RECOVRSP */
+ sscop_ustat_inconn, /* SOS_INRECOV */
+ sscop_ustat_ready, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+/* UD PDU */
+static void (*sscop_ud_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_ud_all, /* SOS_IDLE */
+ sscop_ud_all, /* SOS_OUTCONN */
+ sscop_ud_all, /* SOS_INCONN */
+ sscop_ud_all, /* SOS_OUTDISC */
+ sscop_ud_all, /* SOS_OUTRESYN */
+ sscop_ud_all, /* SOS_INRESYN */
+ sscop_ud_all, /* SOS_OUTRECOV */
+ sscop_ud_all, /* SOS_RECOVRSP */
+ sscop_ud_all, /* SOS_INRECOV */
+ sscop_ud_all, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+/* MD PDU */
+static void (*sscop_md_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_md_all, /* SOS_IDLE */
+ sscop_md_all, /* SOS_OUTCONN */
+ sscop_md_all, /* SOS_INCONN */
+ sscop_md_all, /* SOS_OUTDISC */
+ sscop_md_all, /* SOS_OUTRESYN */
+ sscop_md_all, /* SOS_INRESYN */
+ sscop_md_all, /* SOS_OUTRECOV */
+ sscop_md_all, /* SOS_RECOVRSP */
+ sscop_md_all, /* SOS_INRECOV */
+ sscop_md_all, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+
+/*
+ * PDU type lookup table
+ */
+void (*(*sscop_q2110_pdutab[]))
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL,
+ sscop_bgn_tab,
+ sscop_bgak_tab,
+ sscop_end_tab,
+ sscop_endak_tab,
+ sscop_rs_tab,
+ sscop_rsak_tab,
+ sscop_bgrej_tab,
+ sscop_sd_tab,
+ sscop_er_tab,
+ sscop_poll_tab,
+ sscop_stat_tab,
+ sscop_ustat_tab,
+ sscop_ud_tab,
+ sscop_md_tab,
+ sscop_erak_tab
+};
+
+
+/*
+ * BGN PDU / SOS_OUTCONN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_bgn_outconn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct bgn_pdu *bp = (struct bgn_pdu *)trlr;
+ int err;
+
+ /*
+ * If retransmitted BGN, ignore it
+ */
+ if (sscop_is_rexmit(sop, bp->bgn_nsq)) {
+ KB_FREEALL(m);
+ return;
+ }
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Initialize state variables
+ */
+ SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr));
+ SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin);
+ q2110_init_state(sop);
+
+ /*
+ * Return an ACK to peer
+ */
+ (void) sscop_send_bgak(sop);
+
+ /*
+ * Notify user of connection establishment
+ */
+ STACK_CALL(SSCOP_ESTABLISH_CNF, sop->so_upper, sop->so_toku,
+ sop->so_connvc, (int)m, 0, err);
+ if (err) {
+ KB_FREEALL(m);
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Start data transfer timers
+ */
+ sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll;
+ sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
+
+ /*
+ * OK, we're ready for data
+ */
+ sop->so_state = SOS_READY;
+
+ /*
+ * See if transmit queues need servicing
+ */
+ if (sop->so_flags & SOF_XMITSRVC)
+ sscop_service_xmit(sop);
+
+ return;
+}
+
+
+/*
+ * BGN PDU / SOS_INCONN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_bgn_inconn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct bgn_pdu *bp = (struct bgn_pdu *)trlr;
+ int err;
+
+ /*
+ * If retransmitted BGN, ignore it
+ */
+ if (sscop_is_rexmit(sop, bp->bgn_nsq)) {
+ KB_FREEALL(m);
+ return;
+ }
+
+ /*
+ * Initialize transmit window
+ */
+ SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr));
+
+ /*
+ * First, tell user current connection has been released
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_USER, err);
+ if (err) {
+ KB_FREEALL(m);
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Now, tell user of new connection establishment
+ */
+ STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, (int)m, 0, err);
+ if (err) {
+ KB_FREEALL(m);
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ return;
+}
+
+
+/*
+ * BGN PDU / SOS_READY Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_bgn_ready(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct bgn_pdu *bp = (struct bgn_pdu *)trlr;
+ int err;
+
+ /*
+ * If retransmitted BGN, just ACK it again
+ */
+ if (sscop_is_rexmit(sop, bp->bgn_nsq)) {
+ KB_FREEALL(m);
+ sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
+ (void) sscop_send_bgak(sop);
+ return;
+ }
+
+ /*
+ * Stop data transfer timers
+ */
+ sop->so_timer[SSCOP_T_POLL] = 0;
+ sop->so_timer[SSCOP_T_NORESP] = 0;
+ sop->so_timer[SSCOP_T_IDLE] = 0;
+ sop->so_flags &= ~SOF_KEEPALIVE;
+
+ /*
+ * Initialize transmit window
+ */
+ SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr));
+
+ /*
+ * Clear out appropriate queues
+ */
+ q2110_prep_retrieve(sop);
+
+ /*
+ * Tell user current connection has been released
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_USER, err);
+ if (err) {
+ KB_FREEALL(m);
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Tell user of incoming connection
+ */
+ STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, (int)m, 0, err);
+ if (err) {
+ KB_FREEALL(m);
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Wait for user's response
+ */
+ sop->so_state = SOS_INCONN;
+
+ return;
+}
+
+
+/*
+ * BGREJ PDU / SOS_OUTRECOV Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_bgrej_outrecov(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ int err;
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Report protocol error
+ */
+ sscop_bgrej_error(sop, m, trlr);
+
+ /*
+ * Notify user of connection failure
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
+ if (err) {
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Clear receiver buffer
+ */
+ sscop_rcvr_drain(sop);
+
+ /*
+ * Back to idle state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * END PDU / SOS_OUTRECOV Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_end_outrecov(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct end_pdu *ep = (struct end_pdu *)trlr;
+ int err, source;
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Acknowledge END
+ */
+ (void) sscop_send_endak(sop);
+
+ /*
+ * Get Source value
+ */
+ if (ep->end_type & PT_SOURCE_SSCOP)
+ source = SSCOP_SOURCE_SSCOP;
+ else
+ source = SSCOP_SOURCE_USER;
+
+ /*
+ * Notify user of connection termination
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, (int)m, source, err);
+ if (err) {
+ KB_FREEALL(m);
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Clear receiver buffer
+ */
+ sscop_rcvr_drain(sop);
+
+ /*
+ * Back to idle state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * END PDU / SOS_READY Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_end_ready(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct end_pdu *ep = (struct end_pdu *)trlr;
+ int err, source;
+
+ /*
+ * Stop data transfer timers
+ */
+ sop->so_timer[SSCOP_T_POLL] = 0;
+ sop->so_timer[SSCOP_T_NORESP] = 0;
+ sop->so_timer[SSCOP_T_IDLE] = 0;
+ sop->so_flags &= ~SOF_KEEPALIVE;
+
+ /*
+ * Acknowledge END
+ */
+ (void) sscop_send_endak(sop);
+
+ /*
+ * Get Source value
+ */
+ if (ep->end_type & PT_SOURCE_SSCOP)
+ source = SSCOP_SOURCE_SSCOP;
+ else
+ source = SSCOP_SOURCE_USER;
+
+ /*
+ * Notify user of connection termination
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, (int)m, source, err);
+ if (err) {
+ KB_FREEALL(m);
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Clear out appropriate queues
+ */
+ q2110_prep_retrieve(sop);
+
+ /*
+ * Back to idle state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * ENDAK PDU / SOS_OUTRECOV Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_endak_outrecov(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ int err;
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Report protocol error
+ */
+ sscop_endak_error(sop, m, trlr);
+
+ /*
+ * Notify user of connection failure
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
+ if (err) {
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Clear receiver buffer
+ */
+ sscop_rcvr_drain(sop);
+
+ /*
+ * Back to idle state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * RS PDU / SOS_OUTRESYN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_rs_outresyn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct rs_pdu *rp = (struct rs_pdu *)trlr;
+ int err;
+
+ /*
+ * If retransmitted RS, ignore it
+ */
+ if (sscop_is_rexmit(sop, rp->rs_nsq)) {
+ KB_FREEALL(m);
+ return;
+ }
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Initialize state variables
+ */
+ SEQ_SET(sop->so_sendmax, ntohl(rp->rs_nmr));
+ SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin);
+ q2110_init_state(sop);
+
+ /*
+ * Free PDU buffers
+ */
+ KB_FREEALL(m);
+
+ /*
+ * Return an ACK to peer
+ */
+ (void) sscop_send_rsak(sop);
+
+ /*
+ * Notify user of connection resynchronization
+ */
+ STACK_CALL(SSCOP_RESYNC_CNF, sop->so_upper, sop->so_toku,
+ sop->so_connvc, 0, 0, err);
+ if (err) {
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Start data transfer timers
+ */
+ sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll;
+ sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
+
+ /*
+ * OK, we're ready for data
+ */
+ sop->so_state = SOS_READY;
+
+ /*
+ * See if transmit queues need servicing
+ */
+ if (sop->so_flags & SOF_XMITSRVC)
+ sscop_service_xmit(sop);
+
+ return;
+}
+
+
+/*
+ * RS PDU / SOS_INRESYN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_rs_inresyn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct rs_pdu *rp = (struct rs_pdu *)trlr;
+
+ /*
+ * If retransmitted RS, ignore it
+ */
+ if (sscop_is_rexmit(sop, rp->rs_nsq)) {
+ KB_FREEALL(m);
+ return;
+ }
+
+ /*
+ * Report error condition
+ */
+ sscop_rs_error(sop, m, trlr);
+
+ return;
+}
+
+
+/*
+ * RS PDU / SOS_OUTRECOV Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_rs_outrecov(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct rs_pdu *rp = (struct rs_pdu *)trlr;
+ int err;
+
+ /*
+ * If retransmitted RS, report an error
+ */
+ if (sscop_is_rexmit(sop, rp->rs_nsq)) {
+ sscop_rs_error(sop, m, trlr);
+ return;
+ }
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Initialize transmit window
+ */
+ SEQ_SET(sop->so_sendmax, ntohl(rp->rs_nmr));
+
+ /*
+ * Notify user of connection resynchronization
+ */
+ STACK_CALL(SSCOP_RESYNC_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, (int)m, 0, err);
+ if (err) {
+ KB_FREEALL(m);
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Clear receiver buffer
+ */
+ sscop_rcvr_drain(sop);
+
+ /*
+ * Wait for user response
+ */
+ sop->so_state = SOS_INRESYN;
+
+ return;
+}
+
+
+/*
+ * RS PDU / SOS_READY Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_rs_ready(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct rs_pdu *rp = (struct rs_pdu *)trlr;
+ int err;
+
+ /*
+ * If retransmitted RS, just ACK it
+ */
+ if (sscop_is_rexmit(sop, rp->rs_nsq)) {
+ KB_FREEALL(m);
+ sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
+ sscop_send_rsak(sop);
+ return;
+ }
+
+ /*
+ * Stop data transfer timers
+ */
+ sop->so_timer[SSCOP_T_POLL] = 0;
+ sop->so_timer[SSCOP_T_NORESP] = 0;
+ sop->so_timer[SSCOP_T_IDLE] = 0;
+ sop->so_flags &= ~SOF_KEEPALIVE;
+
+ /*
+ * Initialize transmit window
+ */
+ SEQ_SET(sop->so_sendmax, ntohl(rp->rs_nmr));
+
+ /*
+ * Notify user of connection resynchronization
+ */
+ STACK_CALL(SSCOP_RESYNC_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, (int)m, 0, err);
+ if (err) {
+ KB_FREEALL(m);
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Clear out appropriate queues
+ */
+ q2110_prep_retrieve(sop);
+
+ /*
+ * Wait for user response
+ */
+ sop->so_state = SOS_INRESYN;
+
+ return;
+}
+
+/*
+ * ER PDU / Protocol Error
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_er_error(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+
+ /*
+ * Record error condition
+ */
+ sscop_maa_error(sop, 'L');
+ KB_FREEALL(m);
+
+ return;
+}
+
+
+/*
+ * ER PDU / SOS_IDLE Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_er_idle(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+
+ /*
+ * Record error condition
+ */
+ sscop_er_error(sop, m, trlr);
+
+ /*
+ * Return an END to peer
+ */
+ (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
+
+ return;
+}
+
+
+/*
+ * ER PDU / SOS_OUTRECOV Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_er_outrecov(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct er_pdu *ep = (struct er_pdu *)trlr;
+ int err;
+
+ /*
+ * If retransmitted ER, report an error
+ */
+ if (sscop_is_rexmit(sop, ep->er_nsq)) {
+ sscop_er_error(sop, m, trlr);
+ return;
+ }
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Initialize transmit window
+ */
+ SEQ_SET(sop->so_sendmax, ntohl(ep->er_nmr));
+
+ /*
+ * Initialize receiver window
+ */
+ SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin);
+
+ /*
+ * Free PDU buffers
+ */
+ KB_FREEALL(m);
+
+ /*
+ * Acknowledge ER
+ */
+ (void) sscop_send_erak(sop);
+
+ /*
+ * Deliver any outstanding data to user
+ */
+ q2110_deliver_data(sop);
+
+ /*
+ * Notify user of connection recovery
+ */
+ STACK_CALL(SSCOP_RECOVER_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, 0, 0, err);
+ if (err) {
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Wait for user response
+ */
+ sop->so_state = SOS_RECOVRSP;
+
+ return;
+}
+
+
+/*
+ * ER PDU / SOS_RECOVRSP Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_er_recovrsp(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct er_pdu *ep = (struct er_pdu *)trlr;
+
+ /*
+ * If retransmitted ER, just ACK it
+ */
+ if (sscop_is_rexmit(sop, ep->er_nsq)) {
+ KB_FREEALL(m);
+ (void) sscop_send_erak(sop);
+ return;
+ }
+
+ /*
+ * Report error condition
+ */
+ sscop_er_error(sop, m, trlr);
+
+ return;
+}
+
+
+/*
+ * ER PDU / SOS_INRECOV Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_er_inrecov(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct er_pdu *ep = (struct er_pdu *)trlr;
+
+ /*
+ * If retransmitted ER, just ignore it
+ */
+ if (sscop_is_rexmit(sop, ep->er_nsq)) {
+ KB_FREEALL(m);
+ return;
+ }
+
+ /*
+ * Report error condition
+ */
+ sscop_er_error(sop, m, trlr);
+
+ return;
+}
+
+
+/*
+ * ER PDU / SOS_READY Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_er_ready(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct er_pdu *ep = (struct er_pdu *)trlr;
+ int err;
+
+ /*
+ * If retransmitted ER, just ACK it
+ */
+ if (sscop_is_rexmit(sop, ep->er_nsq)) {
+ KB_FREEALL(m);
+ sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
+ sscop_send_erak(sop);
+ return;
+ }
+
+ /*
+ * Stop data transfer timers
+ */
+ sop->so_timer[SSCOP_T_POLL] = 0;
+ sop->so_timer[SSCOP_T_NORESP] = 0;
+ sop->so_timer[SSCOP_T_IDLE] = 0;
+ sop->so_flags &= ~SOF_KEEPALIVE;
+
+ /*
+ * Initialize transmit window
+ */
+ SEQ_SET(sop->so_sendmax, ntohl(ep->er_nmr));
+
+ /*
+ * Free PDU buffers
+ */
+ KB_FREEALL(m);
+
+ /*
+ * Clear out appropriate queues
+ */
+ q2110_prep_recovery(sop);
+
+ /*
+ * Deliver any outstanding data to user
+ */
+ q2110_deliver_data(sop);
+
+ /*
+ * Notify user of connection recovery
+ */
+ STACK_CALL(SSCOP_RECOVER_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, 0, 0, err);
+ if (err) {
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Wait for user response
+ */
+ sop->so_state = SOS_INRECOV;
+
+ return;
+}
+
+
+/*
+ * ERAK PDU / Protocol Error
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_erak_error(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+
+ /*
+ * Record error condition
+ */
+ sscop_maa_error(sop, 'M');
+ KB_FREEALL(m);
+
+ return;
+}
+
+
+/*
+ * ERAK PDU / SOS_IDLE Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_erak_idle(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+
+ /*
+ * Record error condition
+ */
+ sscop_erak_error(sop, m, trlr);
+
+ /*
+ * Return an END to peer
+ */
+ (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
+
+ return;
+}
+
+
+/*
+ * ERAK PDU / SOS_OUTRECOV Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_erak_outrecov(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct erak_pdu *ep = (struct erak_pdu *)trlr;
+ int err;
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Initialize transmit window
+ */
+ SEQ_SET(sop->so_sendmax, ntohl(ep->erak_nmr));
+
+ /*
+ * Free PDU buffers
+ */
+ KB_FREEALL(m);
+
+ /*
+ * Deliver any outstanding data to user
+ */
+ q2110_deliver_data(sop);
+
+ /*
+ * Notify user of connection recovery
+ */
+ STACK_CALL(SSCOP_RECOVER_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, 0, 0, err);
+ if (err) {
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Wait for user response
+ */
+ sop->so_state = SOS_RECOVRSP;
+
+ return;
+}
+
+
+/*
+ * SD PDU / SOS_READY Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_sd_ready(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct sd_pdu *sp = (struct sd_pdu *)trlr;
+ struct pdu_hdr *php;
+ KBuffer *n;
+ sscop_seq ns;
+ int err, space;
+
+ /*
+ * Get PDU sequence number
+ */
+ SEQ_SET(ns, ntohl(sp->sd_ns));
+
+ /*
+ * Ensure that the sequence number fits within the window
+ */
+ if (SEQ_GEQ(ns, sop->so_rcvmax, sop->so_rcvnext)) {
+ /*
+ * It doesn't, drop received data
+ */
+ KB_FREEALL(m);
+
+ /*
+ * If next highest PDU hasn't reached window end yet,
+ * then send a USTAT to inform transmitter of this gap
+ */
+ if (SEQ_LT(sop->so_rcvhigh, sop->so_rcvmax, sop->so_rcvnext)) {
+ (void) sscop_send_ustat(sop, sop->so_rcvmax);
+ sop->so_rcvhigh = sop->so_rcvmax;
+ }
+ return;
+ }
+
+ /*
+ * If this is the next in-sequence PDU, hand it to user
+ */
+ if (ns == sop->so_rcvnext) {
+ STACK_CALL(SSCOP_DATA_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, (int)m, ns, err);
+ if (err) {
+ KB_FREEALL(m);
+ return;
+ }
+
+ /*
+ * Bump next expected sequence number
+ */
+ SEQ_INCR(sop->so_rcvnext, 1);
+
+ /*
+ * Slide receive window down
+ */
+ SEQ_INCR(sop->so_rcvmax, 1);
+
+ /*
+ * Is this the highest sequence PDU we've received??
+ */
+ if (ns == sop->so_rcvhigh) {
+ /*
+ * Yes, bump the limit and exit
+ */
+ sop->so_rcvhigh = sop->so_rcvnext;
+ return;
+ }
+
+ /*
+ * This is a retransmitted PDU, so see if we have
+ * more in-sequence PDUs already queued up
+ */
+ while ((php = sop->so_recv_hd) &&
+ (php->ph_ns == sop->so_rcvnext)) {
+
+ /*
+ * Yup we do, so remove next PDU from queue and
+ * pass it up to the user as well
+ */
+ sop->so_recv_hd = php->ph_recv_lk;
+ if (sop->so_recv_hd == NULL)
+ sop->so_recv_tl = NULL;
+ STACK_CALL(SSCOP_DATA_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, (int)php->ph_buf, php->ph_ns,
+ err);
+ if (err) {
+ /*
+ * Should never happen, but...
+ */
+ KB_FREEALL(php->ph_buf);
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Bump next expected sequence number
+ */
+ SEQ_INCR(sop->so_rcvnext, 1);
+
+ /*
+ * Slide receive window down
+ */
+ SEQ_INCR(sop->so_rcvmax, 1);
+ }
+
+ /*
+ * Finished with data delivery...
+ */
+ return;
+ }
+
+ /*
+ * We're gonna have to queue this PDU, so find space
+ * for the PDU header
+ */
+ KB_HEADROOM(m, space);
+
+ /*
+ * If there's not enough room in the received buffer,
+ * allocate & link a new buffer for the header
+ */
+ if (space < sizeof(struct pdu_hdr)) {
+
+ KB_ALLOC(n, sizeof(struct pdu_hdr), KB_F_NOWAIT, KB_T_HEADER);
+ if (n == NULL) {
+ KB_FREEALL(m);
+ return;
+ }
+ KB_HEADSET(n, sizeof(struct pdu_hdr));
+ KB_LEN(n) = 0;
+ KB_LINKHEAD(n, m);
+ m = n;
+ }
+
+ /*
+ * Build PDU header
+ *
+ * We can at least assume/require that the start of
+ * the user data is aligned. Also note that we don't
+ * include this header in the buffer len/offset fields.
+ */
+ KB_DATASTART(m, php, struct pdu_hdr *);
+ php--;
+ php->ph_ns = ns;
+ php->ph_buf = m;
+
+ /*
+ * Insert PDU into the receive queue
+ */
+ if (sscop_recv_insert(sop, php)) {
+ /*
+ * Oops, a duplicate sequence number PDU is already on
+ * the queue, somethings wrong here.
+ */
+ sscop_maa_error(sop, 'Q');
+
+ /*
+ * Free buffers
+ */
+ KB_FREEALL(m);
+
+ /*
+ * Go into recovery mode
+ */
+ q2110_error_recovery(sop);
+
+ return;
+ }
+
+ /*
+ * Are we at the high-water mark??
+ */
+ if (ns == sop->so_rcvhigh) {
+ /*
+ * Yes, just bump the mark
+ */
+ SEQ_INCR(sop->so_rcvhigh, 1);
+
+ return;
+ }
+
+ /*
+ * Are we beyond the high-water mark??
+ */
+ if (SEQ_GT(ns, sop->so_rcvhigh, sop->so_rcvnext)) {
+ /*
+ * Yes, then there's a missing PDU, so inform the transmitter
+ */
+ (void) sscop_send_ustat(sop, ns);
+
+ /*
+ * Update high-water mark
+ */
+ sop->so_rcvhigh = SEQ_ADD(ns, 1);
+ }
+
+ return;
+}
+
+
+/*
+ * POLL PDU / SOS_READY Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_poll_ready(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct poll_pdu *pp = (struct poll_pdu *)trlr;
+ sscop_seq nps;
+
+ NTOHL(pp->poll_ns);
+
+ /*
+ * If the poll sequence number is less than highest number
+ * we've already seen, something's wrong
+ */
+ if (SEQ_LT(pp->poll_ns, sop->so_rcvhigh, sop->so_rcvnext)) {
+ /*
+ * Record error condition
+ */
+ sscop_maa_error(sop, 'Q');
+
+ /*
+ * Free buffers
+ */
+ KB_FREEALL(m);
+
+ /*
+ * Go into recovery mode
+ */
+ q2110_error_recovery(sop);
+
+ return;
+ }
+
+ /*
+ * Set a new "next highest" sequence number expected
+ */
+ if (SEQ_LT(pp->poll_ns, sop->so_rcvmax, sop->so_rcvnext))
+ SEQ_SET(sop->so_rcvhigh, pp->poll_ns);
+ else
+ sop->so_rcvhigh = sop->so_rcvmax;
+
+ /*
+ * Return a STAT PDU to peer
+ */
+ SEQ_SET(nps, ntohl(pp->poll_nps));
+ KB_FREEALL(m);
+ (void) sscop_send_stat(sop, nps);
+
+ return;
+}
+
diff --git a/sys/netatm/uni/q2110_subr.c b/sys/netatm/uni/q2110_subr.c
new file mode 100644
index 0000000..4c6036b
--- /dev/null
+++ b/sys/netatm/uni/q2110_subr.c
@@ -0,0 +1,239 @@
+/*
+ *
+ * ===================================
+ * 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: q2110_subr.c,v 1.1 1998/04/07 23:15:20 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * ITU-T Q.2110 - Subroutines
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: q2110_subr.c,v 1.1 1998/04/07 23:15:20 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/uni.h>
+#include <netatm/uni/sscop.h>
+#include <netatm/uni/sscop_misc.h>
+#include <netatm/uni/sscop_pdu.h>
+#include <netatm/uni/sscop_var.h>
+
+
+/*
+ * Conditionally Clear Transmission Queues
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+q2110_clear_xmit(sop)
+ struct sscop *sop;
+{
+ /*
+ * Only clear queues if 'Clear Buffers' == No
+ */
+ if (sop->so_flags & SOF_NOCLRBUF)
+ sscop_xmit_drain(sop);
+}
+
+
+/*
+ * Initialize Data Transfer State Variables
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+q2110_init_state(sop)
+ struct sscop *sop;
+{
+ /*
+ * Initialize for entry into Data Transfer Ready state
+ */
+ sop->so_send = 0;
+ sop->so_pollsend = 0;
+ sop->so_ack = 0;
+ sop->so_pollack = 1;
+ sop->so_polldata = 0;
+ sop->so_rcvhigh = 0;
+ sop->so_rcvnext = 0;
+}
+
+
+/*
+ * Prepare Queues for Data Retrieval
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+q2110_prep_retrieve(sop)
+ struct sscop *sop;
+{
+ /*
+ * If 'Clear Buffers' == No, just clear retransmit queue,
+ * else clear all transmission queues
+ */
+ if (sop->so_flags & SOF_NOCLRBUF) {
+ sop->so_rexmit_hd = NULL;
+ sop->so_rexmit_tl = NULL;
+ } else
+ sscop_xmit_drain(sop);
+
+ /*
+ * Clear receiver queue
+ */
+ sscop_rcvr_drain(sop);
+}
+
+
+/*
+ * Prepare Queues for Error Recovery
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+q2110_prep_recovery(sop)
+ struct sscop *sop;
+{
+ /*
+ * If 'Clear Buffers' == No, just clear retransmit queue,
+ * else clear all transmission queues
+ */
+ if (sop->so_flags & SOF_NOCLRBUF) {
+ sop->so_rexmit_hd = NULL;
+ sop->so_rexmit_tl = NULL;
+ } else
+ sscop_xmit_drain(sop);
+}
+
+
+/*
+ * Conditionally Deliver Received Data to User
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+q2110_deliver_data(sop)
+ struct sscop *sop;
+{
+ /*
+ * If 'Clear Buffers' == No, give data to user
+ */
+ if (sop->so_flags & SOF_NOCLRBUF) {
+ /*
+ * We don't support 'Clear Buffers' == No, so don't bother
+ */
+ }
+
+ /*
+ * Clear receiver queue
+ */
+ sscop_rcvr_drain(sop);
+}
+
+
+/*
+ * Enter Connection Recovery Mode
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+q2110_error_recovery(sop)
+ struct sscop *sop;
+{
+
+ /*
+ * Stop data transfer timers
+ */
+ sop->so_timer[SSCOP_T_POLL] = 0;
+ sop->so_timer[SSCOP_T_NORESP] = 0;
+ sop->so_timer[SSCOP_T_IDLE] = 0;
+ sop->so_flags &= ~SOF_KEEPALIVE;
+
+ /*
+ * Initialize receiver window
+ */
+ SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin);
+
+ /*
+ * Send first ER PDU
+ */
+ sop->so_connctl = 1;
+ SEQ_INCR(sop->so_sendconn, 1);
+ (void) sscop_send_er(sop);
+
+ /*
+ * Set retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc;
+
+ /*
+ * Clear out appropriate queues
+ */
+ q2110_prep_recovery(sop);
+
+ /*
+ * Wait for ERAK
+ */
+ sop->so_state = SOS_OUTRECOV;
+
+ return;
+}
+
diff --git a/sys/netatm/uni/qsaal1_sigaa.c b/sys/netatm/uni/qsaal1_sigaa.c
new file mode 100644
index 0000000..f3b0097
--- /dev/null
+++ b/sys/netatm/uni/qsaal1_sigaa.c
@@ -0,0 +1,518 @@
+/*
+ *
+ * ===================================
+ * 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: qsaal1_sigaa.c,v 1.7 1998/08/26 23:29:18 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * ITU-T Q.SAAL1 - Process AA-signals (SAP_SSCOP)
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: qsaal1_sigaa.c,v 1.7 1998/08/26 23:29:18 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/uni.h>
+#include <netatm/uni/sscop.h>
+#include <netatm/uni/sscop_misc.h>
+#include <netatm/uni/sscop_pdu.h>
+#include <netatm/uni/sscop_var.h>
+
+
+/*
+ * Local functions
+ */
+static void sscop_estreq_ready __P((struct sscop *, int, int));
+static void sscop_datreq_outconn __P((struct sscop *, int, int));
+static void sscop_resreq_ready __P((struct sscop *, int, int));
+static void sscop_resrsp_inresyn __P((struct sscop *, int, int));
+static void sscop_resrsp_conresyn __P((struct sscop *, int, int));
+
+
+/*
+ * Stack command state lookup tables
+ */
+/* SSCOP_INIT */
+static void (*sscop_init_tab[SOS_NUMSTATES])
+ __P((struct sscop *, int, int)) = {
+ sscop_init_inst, /* SOS_INST */
+ NULL, /* SOS_IDLE */
+ NULL, /* SOS_OUTCONN */
+ NULL, /* SOS_INCONN */
+ NULL, /* SOS_OUTDISC */
+ NULL, /* SOS_OUTRESYN */
+ NULL, /* SOS_INRESYN */
+ NULL, /* SOS_CONRESYN */
+ NULL, /* invalid */
+ NULL, /* invalid */
+ NULL, /* SOS_READY */
+ NULL /* SOS_TERM */
+};
+
+/* SSCOP_TERM */
+static void (*sscop_term_tab[SOS_NUMSTATES])
+ __P((struct sscop *, int, int)) = {
+ sscop_term_all, /* SOS_INST */
+ sscop_term_all, /* SOS_IDLE */
+ sscop_term_all, /* SOS_OUTCONN */
+ sscop_term_all, /* SOS_INCONN */
+ sscop_term_all, /* SOS_OUTDISC */
+ sscop_term_all, /* SOS_OUTRESYN */
+ sscop_term_all, /* SOS_INRESYN */
+ sscop_term_all, /* SOS_CONRESYN */
+ NULL, /* invalid */
+ NULL, /* invalid */
+ sscop_term_all, /* SOS_READY */
+ sscop_term_all /* SOS_TERM */
+};
+
+/* SSCOP_ESTABLISH_REQ */
+static void (*sscop_estreq_tab[SOS_NUMSTATES])
+ __P((struct sscop *, int, int)) = {
+ NULL, /* SOS_INST */
+ sscop_estreq_idle, /* SOS_IDLE */
+ NULL, /* SOS_OUTCONN */
+ NULL, /* SOS_INCONN */
+ sscop_estreq_ready, /* SOS_OUTDISC */
+ sscop_estreq_ready, /* SOS_OUTRESYN */
+ sscop_estreq_ready, /* SOS_INRESYN */
+ sscop_estreq_ready, /* SOS_CONRESYN */
+ NULL, /* invalid */
+ NULL, /* invalid */
+ sscop_estreq_ready, /* SOS_READY */
+ sscop_aa_noop_1 /* SOS_TERM */
+};
+
+/* SSCOP_ESTABLISH_RSP */
+static void (*sscop_estrsp_tab[SOS_NUMSTATES])
+ __P((struct sscop *, int, int)) = {
+ NULL, /* SOS_INST */
+ NULL, /* SOS_IDLE */
+ NULL, /* SOS_OUTCONN */
+ sscop_estrsp_inconn, /* SOS_INCONN */
+ NULL, /* SOS_OUTDISC */
+ NULL, /* SOS_OUTRESYN */
+ NULL, /* SOS_INRESYN */
+ NULL, /* SOS_CONRESYN */
+ NULL, /* invalid */
+ NULL, /* invalid */
+ sscop_aa_noop_1, /* SOS_READY */
+ sscop_aa_noop_1 /* SOS_TERM */
+};
+
+/* SSCOP_RELEASE_REQ */
+static void (*sscop_relreq_tab[SOS_NUMSTATES])
+ __P((struct sscop *, int, int)) = {
+ NULL, /* SOS_INST */
+ NULL, /* SOS_IDLE */
+ sscop_relreq_outconn, /* SOS_OUTCONN */
+ sscop_relreq_inconn, /* SOS_INCONN */
+ NULL, /* SOS_OUTDISC */
+ sscop_relreq_outconn, /* SOS_OUTRESYN */
+ sscop_relreq_ready, /* SOS_INRESYN */
+ sscop_relreq_outconn, /* SOS_CONRESYN */
+ NULL, /* invalid */
+ NULL, /* invalid */
+ sscop_relreq_ready, /* SOS_READY */
+ sscop_aa_noop_1 /* SOS_TERM */
+};
+
+/* SSCOP_DATA_REQ */
+static void (*sscop_datreq_tab[SOS_NUMSTATES])
+ __P((struct sscop *, int, int)) = {
+ NULL, /* SOS_INST */
+ NULL, /* SOS_IDLE */
+ sscop_datreq_outconn, /* SOS_OUTCONN */
+ NULL, /* SOS_INCONN */
+ NULL, /* SOS_OUTDISC */
+ NULL, /* SOS_OUTRESYN */
+ sscop_datreq_ready, /* SOS_INRESYN */
+ NULL, /* SOS_CONRESYN */
+ NULL, /* invalid */
+ NULL, /* invalid */
+ sscop_datreq_ready, /* SOS_READY */
+ sscop_aa_noop_1 /* SOS_TERM */
+};
+
+/* SSCOP_RESYNC_REQ */
+static void (*sscop_resreq_tab[SOS_NUMSTATES])
+ __P((struct sscop *, int, int)) = {
+ NULL, /* SOS_INST */
+ NULL, /* SOS_IDLE */
+ NULL, /* SOS_OUTCONN */
+ NULL, /* SOS_INCONN */
+ NULL, /* SOS_OUTDISC */
+ NULL, /* SOS_OUTRESYN */
+ NULL, /* SOS_INRESYN */
+ NULL, /* SOS_CONRESYN */
+ NULL, /* invalid */
+ NULL, /* invalid */
+ sscop_resreq_ready, /* SOS_READY */
+ sscop_aa_noop_1 /* SOS_TERM */
+};
+
+/* SSCOP_RESYNC_RSP */
+static void (*sscop_resrsp_tab[SOS_NUMSTATES])
+ __P((struct sscop *, int, int)) = {
+ NULL, /* SOS_INST */
+ NULL, /* SOS_IDLE */
+ NULL, /* SOS_OUTCONN */
+ NULL, /* SOS_INCONN */
+ NULL, /* SOS_OUTDISC */
+ NULL, /* SOS_OUTRESYN */
+ sscop_resrsp_inresyn, /* SOS_INRESYN */
+ sscop_resrsp_conresyn, /* SOS_CONRESYN */
+ NULL, /* invalid */
+ NULL, /* invalid */
+ NULL, /* SOS_READY */
+ sscop_aa_noop_0 /* SOS_TERM */
+};
+
+/* SSCOP_UNITDATA_REQ */
+static void (*sscop_udtreq_tab[SOS_NUMSTATES])
+ __P((struct sscop *, int, int)) = {
+ NULL, /* SOS_INST */
+ sscop_udtreq_all, /* SOS_IDLE */
+ sscop_udtreq_all, /* SOS_OUTCONN */
+ sscop_udtreq_all, /* SOS_INCONN */
+ sscop_udtreq_all, /* SOS_OUTDISC */
+ sscop_udtreq_all, /* SOS_OUTRESYN */
+ sscop_udtreq_all, /* SOS_INRESYN */
+ sscop_udtreq_all, /* SOS_CONRESYN */
+ NULL, /* invalid */
+ NULL, /* invalid */
+ sscop_udtreq_all, /* SOS_READY */
+ sscop_aa_noop_1 /* SOS_TERM */
+};
+
+
+/*
+ * Stack command lookup table
+ */
+void (*(*sscop_qsaal_aatab[SSCOP_CMD_SIZE]))
+ __P((struct sscop *, int, int)) = {
+ NULL,
+ sscop_init_tab,
+ sscop_term_tab,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ sscop_estreq_tab,
+ NULL,
+ sscop_estrsp_tab,
+ NULL,
+ sscop_relreq_tab,
+ NULL,
+ NULL,
+ sscop_datreq_tab,
+ NULL,
+ sscop_resreq_tab,
+ NULL,
+ sscop_resrsp_tab,
+ NULL,
+ NULL,
+ NULL,
+ sscop_udtreq_tab,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+
+/*
+ * SSCOP_ESTABLISH_REQ / SOS_READY Command Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * arg1 pointer to buffer containing SSCOP-UU data
+ * arg2 buffer release parameter
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_estreq_ready(sop, arg1, arg2)
+ struct sscop *sop;
+ int arg1;
+ int arg2;
+{
+
+ /*
+ * We don't support SSCOP-UU data
+ */
+ if (arg1 != SSCOP_UU_NULL)
+ KB_FREEALL((KBuffer *)arg1);
+
+ /*
+ * We currently only support BR=YES
+ */
+ if (arg2 != SSCOP_BR_YES) {
+ sscop_abort(sop, "sscop: BR != YES\n");
+ return;
+ }
+
+ /*
+ * Stop poll timer
+ */
+ sop->so_timer[SSCOP_T_POLL] = 0;
+ sop->so_flags &= ~SOF_KEEPALIVE;
+
+ /*
+ * Stop lost poll/stat timer
+ */
+ sop->so_timer[SSCOP_T_NORESP] = 0;
+
+ /*
+ * Initialize receiver window
+ */
+ SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin);
+
+ /*
+ * Send first BGN PDU
+ */
+ sop->so_connctl = 1;
+ (void) sscop_send_bgn(sop, SSCOP_SOURCE_USER);
+
+ /*
+ * Reset transmitter state
+ */
+ qsaal1_reset_xmit(sop);
+
+ /*
+ * Set retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc;
+
+ /*
+ * Wait for BGAK
+ */
+ sop->so_state = SOS_OUTCONN;
+
+ return;
+}
+
+
+/*
+ * SSCOP_DATA_REQ / SOS_OUTCONN Command Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * arg1 pointer to buffer containing assured user data
+ * arg2 unused
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_datreq_outconn(sop, arg1, arg2)
+ struct sscop *sop;
+ int arg1;
+ int arg2;
+{
+ KBuffer *m = (KBuffer *)arg1;
+
+ /*
+ * We must have a buffer (even if it contains no data)
+ */
+ if (m == NULL) {
+ sscop_abort(sop, "sscop_datreq_outconn: no buffer\n");
+ return;
+ }
+
+ /*
+ * Only accept data here if in the middle of an SSCOP-initiated
+ * session reestablishment
+ */
+ if ((sop->so_flags & SOF_REESTAB) == 0) {
+ KB_FREEALL(m);
+ sscop_abort(sop, "sscop_datreq_outconn: data not allowed\n");
+ return;
+ }
+
+ /*
+ * Place data at end of transmission queue
+ */
+ KB_QNEXT(m) = NULL;
+ if (sop->so_xmit_hd == NULL)
+ sop->so_xmit_hd = m;
+ else
+ KB_QNEXT(sop->so_xmit_tl) = m;
+ sop->so_xmit_tl = m;
+
+ /*
+ * Note that the transmit queues need to be serviced
+ */
+ sop->so_flags |= SOF_XMITSRVC;
+
+ return;
+}
+
+
+/*
+ * SSCOP_RESYNC_REQ / SOS_READY Command Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * arg1 pointer to buffer containing SSCOP-UU data
+ * arg2 unused
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_resreq_ready(sop, arg1, arg2)
+ struct sscop *sop;
+ int arg1;
+ int arg2;
+{
+
+ /*
+ * We don't support SSCOP-UU data
+ */
+ if (arg1 != SSCOP_UU_NULL)
+ KB_FREEALL((KBuffer *)arg1);
+
+ /*
+ * Stop poll timer
+ */
+ sop->so_timer[SSCOP_T_POLL] = 0;
+ sop->so_flags &= ~SOF_KEEPALIVE;
+
+ /*
+ * Stop lost poll/stat timer
+ */
+ sop->so_timer[SSCOP_T_NORESP] = 0;
+
+ /*
+ * Send first RS PDU
+ */
+ sop->so_connctl = 1;
+ (void) sscop_send_rs(sop);
+
+ /*
+ * Reset transmitter state
+ */
+ qsaal1_reset_xmit(sop);
+
+ /*
+ * Set retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc;
+
+ /*
+ * Wait for RSAK
+ */
+ sop->so_state = SOS_OUTRESYN;
+
+ return;
+}
+
+
+/*
+ * SSCOP_RESYNC_RSP / SOS_INRESYN Command Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * arg1 unused
+ * arg2 unused
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_resrsp_inresyn(sop, arg1, arg2)
+ struct sscop *sop;
+ int arg1;
+ int arg2;
+{
+
+ /*
+ * Send RSAK PDU
+ */
+ (void) sscop_send_rsak(sop);
+
+ /*
+ * Back to data transfer state
+ */
+ sop->so_state = SOS_READY;
+
+ return;
+}
+
+
+/*
+ * SSCOP_RESYNC_RSP / SOS_CONRESYN Command Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * arg1 unused
+ * arg2 unused
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_resrsp_conresyn(sop, arg1, arg2)
+ struct sscop *sop;
+ int arg1;
+ int arg2;
+{
+
+ /*
+ * Send RSAK PDU
+ */
+ (void) sscop_send_rsak(sop);
+
+ /*
+ * Back to waiting for peer's RSAK
+ */
+ sop->so_state = SOS_OUTRESYN;
+
+ return;
+}
+
diff --git a/sys/netatm/uni/qsaal1_sigcpcs.c b/sys/netatm/uni/qsaal1_sigcpcs.c
new file mode 100644
index 0000000..1d62165
--- /dev/null
+++ b/sys/netatm/uni/qsaal1_sigcpcs.c
@@ -0,0 +1,1545 @@
+/*
+ *
+ * ===================================
+ * 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: qsaal1_sigcpcs.c,v 1.7 1998/04/07 23:21:03 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * ITU-T Q.SAAL1 - Process CPCS-signals (SSCOP PDUs)
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: qsaal1_sigcpcs.c,v 1.7 1998/04/07 23:21:03 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/uni.h>
+#include <netatm/uni/sscop.h>
+#include <netatm/uni/sscop_misc.h>
+#include <netatm/uni/sscop_pdu.h>
+#include <netatm/uni/sscop_var.h>
+
+
+/*
+ * Local functions
+ */
+static void sscop_bgn_outconn __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_end_outresyn __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_end_conresyn __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_end_ready __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_endak_outresyn __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_rs_outresyn __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_rs_ready __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_rsak_conresyn __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_sd_inresyn __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_sd_conresyn __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_sd_process __P((struct sscop *, KBuffer *, caddr_t, int));
+static void sscop_sd_ready __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_sdp_ready __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_poll_inresyn __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_poll_conresyn __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_poll_ready __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_stat_conresyn __P((struct sscop *, KBuffer *, caddr_t));
+static void sscop_ustat_conresyn __P((struct sscop *, KBuffer *, caddr_t));
+
+
+/*
+ * PDU type state lookup tables
+ */
+/* BGN PDU */
+static void (*sscop_bgn_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_bgn_idle, /* SOS_IDLE */
+ sscop_bgn_outconn, /* SOS_OUTCONN */
+ sscop_noop, /* SOS_INCONN */
+ sscop_bgn_outdisc, /* SOS_OUTDISC */
+ sscop_bgn_outresyn, /* SOS_OUTRESYN */
+ sscop_bgn_inresyn, /* SOS_INRESYN */
+ sscop_bgn_outresyn, /* SOS_CONRESYN */
+ NULL, /* invalid */
+ NULL, /* invalid */
+ sscop_bgn_inresyn, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+/* BGAK PDU */
+static void (*sscop_bgak_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_bgak_idle, /* SOS_IDLE */
+ sscop_bgak_outconn, /* SOS_OUTCONN */
+ sscop_bgak_error, /* SOS_INCONN */
+ sscop_noop, /* SOS_OUTDISC */
+ sscop_bgak_error, /* SOS_OUTRESYN */
+ sscop_bgak_error, /* SOS_INRESYN */
+ sscop_bgak_error, /* SOS_CONRESYN */
+ NULL, /* invalid */
+ NULL, /* invalid */
+ sscop_noop, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+/* BGREJ PDU */
+static void (*sscop_bgrej_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_bgrej_error, /* SOS_IDLE */
+ sscop_bgrej_outconn, /* SOS_OUTCONN */
+ sscop_bgrej_inconn, /* SOS_INCONN */
+ sscop_noop, /* SOS_OUTDISC */
+ sscop_bgrej_outresyn, /* SOS_OUTRESYN */
+ sscop_bgrej_ready, /* SOS_INRESYN */
+ sscop_bgrej_outresyn, /* SOS_CONRESYN */
+ NULL, /* invalid */
+ NULL, /* invalid */
+ sscop_bgrej_ready, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+/* END PDU */
+static void (*sscop_end_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_end_idle, /* SOS_IDLE */
+ sscop_noop, /* SOS_OUTCONN */
+ sscop_end_inconn, /* SOS_INCONN */
+ sscop_end_outdisc, /* SOS_OUTDISC */
+ sscop_end_outresyn, /* SOS_OUTRESYN */
+ sscop_end_ready, /* SOS_INRESYN */
+ sscop_end_conresyn, /* SOS_CONRESYN */
+ NULL, /* invalid */
+ NULL, /* invalid */
+ sscop_end_ready, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+/* ENDAK PDU */
+static void (*sscop_endak_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_noop, /* SOS_IDLE */
+ sscop_noop, /* SOS_OUTCONN */
+ sscop_endak_inconn, /* SOS_INCONN */
+ sscop_endak_outdisc, /* SOS_OUTDISC */
+ sscop_endak_outresyn, /* SOS_OUTRESYN */
+ sscop_endak_ready, /* SOS_INRESYN */
+ sscop_endak_outresyn, /* SOS_CONRESYN */
+ NULL, /* invalid */
+ NULL, /* invalid */
+ sscop_endak_ready, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+/* RS PDU */
+static void (*sscop_rs_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_rs_idle, /* SOS_IDLE */
+ sscop_noop, /* SOS_OUTCONN */
+ sscop_rs_error, /* SOS_INCONN */
+ sscop_noop, /* SOS_OUTDISC */
+ sscop_rs_outresyn, /* SOS_OUTRESYN */
+ sscop_noop, /* SOS_INRESYN */
+ sscop_noop, /* SOS_CONRESYN */
+ NULL, /* invalid */
+ NULL, /* invalid */
+ sscop_rs_ready, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+/* RSAK PDU */
+static void (*sscop_rsak_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_rsak_idle, /* SOS_IDLE */
+ sscop_noop, /* SOS_OUTCONN */
+ sscop_rsak_error, /* SOS_INCONN */
+ sscop_noop, /* SOS_OUTDISC */
+ sscop_rsak_outresyn, /* SOS_OUTRESYN */
+ sscop_rsak_error, /* SOS_INRESYN */
+ sscop_rsak_conresyn, /* SOS_CONRESYN */
+ NULL, /* invalid */
+ NULL, /* invalid */
+ sscop_rsak_error, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+/* SD PDU */
+static void (*sscop_sd_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_sd_idle, /* SOS_IDLE */
+ sscop_noop, /* SOS_OUTCONN */
+ sscop_sd_inconn, /* SOS_INCONN */
+ sscop_noop, /* SOS_OUTDISC */
+ sscop_sd_ready, /* SOS_OUTRESYN */
+ sscop_sd_inresyn, /* SOS_INRESYN */
+ sscop_sd_conresyn, /* SOS_CONRESYN */
+ NULL, /* invalid */
+ NULL, /* invalid */
+ sscop_sd_ready, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+/* SDP PDU */
+static void (*sscop_sdp_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_sd_idle, /* SOS_IDLE */
+ sscop_noop, /* SOS_OUTCONN */
+ sscop_sd_inconn, /* SOS_INCONN */
+ sscop_noop, /* SOS_OUTDISC */
+ sscop_sdp_ready, /* SOS_OUTRESYN */
+ sscop_sd_inresyn, /* SOS_INRESYN */
+ sscop_sd_conresyn, /* SOS_CONRESYN */
+ NULL, /* invalid */
+ NULL, /* invalid */
+ sscop_sdp_ready, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+/* POLL PDU */
+static void (*sscop_poll_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_poll_idle, /* SOS_IDLE */
+ sscop_noop, /* SOS_OUTCONN */
+ sscop_poll_inconn, /* SOS_INCONN */
+ sscop_noop, /* SOS_OUTDISC */
+ sscop_poll_ready, /* SOS_OUTRESYN */
+ sscop_poll_inresyn, /* SOS_INRESYN */
+ sscop_poll_conresyn, /* SOS_CONRESYN */
+ NULL, /* invalid */
+ NULL, /* invalid */
+ sscop_poll_ready, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+/* STAT PDU */
+static void (*sscop_stat_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_stat_idle, /* SOS_IDLE */
+ sscop_noop, /* SOS_OUTCONN */
+ sscop_stat_inconn, /* SOS_INCONN */
+ sscop_noop, /* SOS_OUTDISC */
+ sscop_noop, /* SOS_OUTRESYN */
+ sscop_stat_ready, /* SOS_INRESYN */
+ sscop_stat_conresyn, /* SOS_CONRESYN */
+ NULL, /* invalid */
+ NULL, /* invalid */
+ sscop_stat_ready, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+/* USTAT PDU */
+static void (*sscop_ustat_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_ustat_idle, /* SOS_IDLE */
+ sscop_noop, /* SOS_OUTCONN */
+ sscop_ustat_inconn, /* SOS_INCONN */
+ sscop_noop, /* SOS_OUTDISC */
+ sscop_noop, /* SOS_OUTRESYN */
+ sscop_ustat_ready, /* SOS_INRESYN */
+ sscop_ustat_conresyn, /* SOS_CONRESYN */
+ NULL, /* invalid */
+ NULL, /* invalid */
+ sscop_ustat_ready, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+/* UD PDU */
+static void (*sscop_ud_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_ud_all, /* SOS_IDLE */
+ sscop_ud_all, /* SOS_OUTCONN */
+ sscop_ud_all, /* SOS_INCONN */
+ sscop_ud_all, /* SOS_OUTDISC */
+ sscop_ud_all, /* SOS_OUTRESYN */
+ sscop_ud_all, /* SOS_INRESYN */
+ sscop_ud_all, /* SOS_CONRESYN */
+ NULL, /* invalid */
+ NULL, /* invalid */
+ sscop_ud_all, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+/* MD PDU */
+static void (*sscop_md_tab[SOS_NUMSTATES])
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL, /* SOS_INST */
+ sscop_md_all, /* SOS_IDLE */
+ sscop_md_all, /* SOS_OUTCONN */
+ sscop_md_all, /* SOS_INCONN */
+ sscop_md_all, /* SOS_OUTDISC */
+ sscop_md_all, /* SOS_OUTRESYN */
+ sscop_md_all, /* SOS_INRESYN */
+ sscop_md_all, /* SOS_CONRESYN */
+ NULL, /* invalid */
+ NULL, /* invalid */
+ sscop_md_all, /* SOS_READY */
+ sscop_noop /* SOS_TERM */
+};
+
+
+/*
+ * PDU type lookup table
+ */
+void (*(*sscop_qsaal_pdutab[]))
+ __P((struct sscop *, KBuffer *, caddr_t)) = {
+ NULL,
+ sscop_bgn_tab,
+ sscop_bgak_tab,
+ sscop_end_tab,
+ sscop_endak_tab,
+ sscop_rs_tab,
+ sscop_rsak_tab,
+ sscop_bgrej_tab,
+ sscop_sd_tab,
+ sscop_sdp_tab,
+ sscop_poll_tab,
+ sscop_stat_tab,
+ sscop_ustat_tab,
+ sscop_ud_tab,
+ sscop_md_tab,
+ NULL
+};
+
+
+/*
+ * BGN PDU / SOS_OUTCONN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_bgn_outconn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct bgn_pdu *bp = (struct bgn_pdu *)trlr;
+ int err;
+
+ /*
+ * Initialize transmit window
+ */
+ SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr));
+
+ /*
+ * Notify user of connection establishment
+ */
+ if (sop->so_flags & SOF_REESTAB) {
+ KB_FREEALL(m);
+ STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
+ if (err) {
+ sscop_abort(sop, "sscop_bgn_outconn: stack memory\n");
+ return;
+ }
+ sop->so_flags &= ~SOF_REESTAB;
+ } else {
+ STACK_CALL(SSCOP_ESTABLISH_CNF, sop->so_upper, sop->so_toku,
+ sop->so_connvc, (int)m, 0, err);
+ if (err) {
+ KB_FREEALL(m);
+ sscop_abort(sop, "sscop_bgn_outconn: stack memory\n");
+ return;
+ }
+ }
+
+ /*
+ * Return an ACK to peer
+ */
+ (void) sscop_send_bgak(sop);
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Reset receiver variables
+ */
+ qsaal1_reset_rcvr(sop);
+
+ /*
+ * Start polling timer
+ */
+ sscop_set_poll(sop);
+
+ /*
+ * Start lost poll/stat timer
+ */
+ sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
+
+ /*
+ * OK, we're ready for data
+ */
+ sop->so_state = SOS_READY;
+
+ /*
+ * See if transmit queues need servicing
+ */
+ if (sop->so_flags & SOF_XMITSRVC)
+ sscop_service_xmit(sop);
+
+ return;
+}
+
+
+/*
+ * END PDU / SOS_OUTRESYN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_end_outresyn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct end_pdu *ep = (struct end_pdu *)trlr;
+ int err, source;
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Acknowledge END
+ */
+ (void) sscop_send_endak(sop);
+
+ /*
+ * Get Source value
+ */
+ if (ep->end_type & PT_SOURCE_SSCOP)
+ source = SSCOP_SOURCE_SSCOP;
+ else
+ source = SSCOP_SOURCE_USER;
+
+ /*
+ * Notify user of connection termination
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, (int)m, source, err);
+ if (err) {
+ KB_FREEALL(m);
+ sscop_abort(sop, "sscop_end_outresyn: stack memory\n");
+ return;
+ }
+
+ /*
+ * Clear connection data
+ */
+ qsaal1_clear_connection(sop);
+
+ /*
+ * Back to idle state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * END PDU / SOS_CONRESYN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_end_conresyn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ int err;
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Free up buffers
+ */
+ KB_FREEALL(m);
+
+ /*
+ * Acknowledge END
+ */
+ (void) sscop_send_endak(sop);
+
+ /*
+ * Notify user of connection termination
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
+ if (err) {
+ sscop_abort(sop, "sscop_end_conresyn: stack memory\n");
+ return;
+ }
+
+ /*
+ * Clear connection data
+ */
+ qsaal1_clear_connection(sop);
+
+ /*
+ * Back to idle state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * END PDU / SOS_READY Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_end_ready(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct end_pdu *ep = (struct end_pdu *)trlr;
+ int err, source;
+
+ /*
+ * Stop poll timer
+ */
+ sop->so_timer[SSCOP_T_POLL] = 0;
+ sop->so_flags &= ~SOF_KEEPALIVE;
+
+ /*
+ * Stop lost poll/stat timer
+ */
+ sop->so_timer[SSCOP_T_NORESP] = 0;
+
+ /*
+ * Acknowledge END
+ */
+ (void) sscop_send_endak(sop);
+
+ /*
+ * Get Source value
+ */
+ if (ep->end_type & PT_SOURCE_SSCOP)
+ source = SSCOP_SOURCE_SSCOP;
+ else
+ source = SSCOP_SOURCE_USER;
+
+ /*
+ * Notify user of connection termination
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, (int)m, source, err);
+ if (err) {
+ KB_FREEALL(m);
+ sscop_abort(sop, "sscop_end_ready: stack memory\n");
+ return;
+ }
+
+ /*
+ * Clear connection data
+ */
+ qsaal1_clear_connection(sop);
+
+ /*
+ * Back to idle state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * ENDAK PDU / SOS_OUTRESYN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_endak_outresyn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ int err;
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Report protocol error
+ */
+ sscop_endak_error(sop, m, trlr);
+
+ /*
+ * Notify user of connection failure
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
+ if (err) {
+ sscop_abort(sop, "sscop_endak_outresyn: stack memory\n");
+ return;
+ }
+
+ /*
+ * Clear connection data
+ */
+ qsaal1_clear_connection(sop);
+
+ /*
+ * Back to idle state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * RS PDU / SOS_OUTRESYN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_rs_outresyn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ int err;
+
+ /*
+ * Notify user of resynchronization
+ */
+ STACK_CALL(SSCOP_RESYNC_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, (int)m, 0, err);
+ if (err) {
+ KB_FREEALL(m);
+ sscop_abort(sop, "sscop_rs_outresyn: stack memory\n");
+ return;
+ }
+
+ /*
+ * Reset receiver state variables
+ */
+ qsaal1_reset_rcvr(sop);
+
+ /*
+ * Wait for both peer and user responses
+ */
+ sop->so_state = SOS_CONRESYN;
+
+ return;
+}
+
+
+/*
+ * RS PDU / SOS_READY Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_rs_ready(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ int err;
+
+ /*
+ * Notify user of resynchronization
+ */
+ STACK_CALL(SSCOP_RESYNC_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, (int)m, 0, err);
+ if (err) {
+ KB_FREEALL(m);
+ sscop_abort(sop, "sscop_rs_ready: stack memory\n");
+ return;
+ }
+
+ /*
+ * Reset receiver state variables
+ */
+ qsaal1_reset_rcvr(sop);
+
+ /*
+ * Wait for user response
+ */
+ sop->so_state = SOS_INRESYN;
+
+ return;
+}
+
+
+/*
+ * RSAK PDU / SOS_CONRESYN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_rsak_conresyn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ int err;
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Free buffers
+ */
+ KB_FREEALL(m);
+
+ /*
+ * Notify user of resynchronization completion
+ */
+ STACK_CALL(SSCOP_RESYNC_CNF, sop->so_upper, sop->so_toku,
+ sop->so_connvc, 0, 0, err);
+ if (err) {
+ sscop_abort(sop, "sscop_rsak_conresyn: stack memory\n");
+ return;
+ }
+
+ /*
+ * Start the polling timer
+ */
+ sscop_set_poll(sop);
+
+ /*
+ * Start lost poll/stat timer
+ */
+ sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
+
+ /*
+ * Continue waiting for user response
+ */
+ sop->so_state = SOS_INRESYN;
+
+ /*
+ * See if transmit queues need servicing
+ */
+ if (sop->so_flags & SOF_XMITSRVC)
+ sscop_service_xmit(sop);
+
+ return;
+}
+
+
+/*
+ * SD PDU / SOS_INRESYN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_sd_inresyn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ int err;
+
+ /*
+ * Stop poll timer
+ */
+ sop->so_timer[SSCOP_T_POLL] = 0;
+ sop->so_flags &= ~SOF_KEEPALIVE;
+
+ /*
+ * Stop lost poll/stat timer
+ */
+ sop->so_timer[SSCOP_T_NORESP] = 0;
+
+ /*
+ * Record error condition
+ */
+ sscop_sd_error(sop, m, trlr);
+
+ /*
+ * Return an END to peer
+ */
+ (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
+
+ /*
+ * Notify user of connection failure
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
+ if (err) {
+ sscop_abort(sop, "sscop_sd_inresyn: stack memory\n");
+ return;
+ }
+
+ /*
+ * Clear connection data
+ */
+ qsaal1_clear_connection(sop);
+
+ /*
+ * Go back to idle state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * SD PDU / SOS_CONRESYN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_sd_conresyn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ int err;
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Record error condition
+ */
+ sscop_sd_error(sop, m, trlr);
+
+ /*
+ * Return an END to peer
+ */
+ (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
+
+ /*
+ * Notify user of connection failure
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
+ if (err) {
+ sscop_abort(sop, "sscop_sd_conresyn: stack memory\n");
+ return;
+ }
+
+ /*
+ * Clear connection data
+ */
+ qsaal1_clear_connection(sop);
+
+ /*
+ * Go back to idle state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * SD/SDP PDU Common Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU user data buffer chain
+ * trlr pointer to PDU trailer
+ * type PDU type (SD or SDP)
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_sd_process(sop, m, trlr, type)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+ int type;
+{
+ struct sd_pdu *sp;
+ struct sdp_pdu *spp;
+ struct poll_pdu poll;
+ struct pdu_hdr *php;
+ KBuffer *n;
+ sscop_seq ns, nps;
+ int err, space;
+
+ /*
+ * Get PDU sequence number(s)
+ */
+ if (type == PT_SD) {
+ sp = (struct sd_pdu *)trlr;
+ SEQ_SET(ns, ntohl(sp->sd_ns));
+ SEQ_SET(nps, 0);
+ } else {
+ spp = (struct sdp_pdu *)trlr;
+ SEQ_SET(ns, ntohl(spp->sdp_ns));
+ SEQ_SET(nps, ntohl(spp->sdp_nps));
+ }
+
+ /*
+ * Ensure that the sequence number fits within the window
+ */
+ if (SEQ_GEQ(ns, sop->so_rcvmax, sop->so_rcvnext)) {
+ KB_FREEALL(m);
+ return;
+ }
+
+ /*
+ * If this is the next in-sequence PDU, hand it to user
+ */
+ if (ns == sop->so_rcvnext) {
+ STACK_CALL(SSCOP_DATA_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, (int)m, ns, err);
+ if (err) {
+ KB_FREEALL(m);
+ return;
+ }
+
+ /*
+ * Bump next expected sequence number
+ */
+ SEQ_INCR(sop->so_rcvnext, 1);
+
+ /*
+ * Slide receive window down
+ */
+ SEQ_INCR(sop->so_rcvmax, 1);
+
+ /*
+ * Is this the highest sequence PDU we've received??
+ */
+ if (ns == sop->so_rcvhigh) {
+ /*
+ * Yes, bump the limit and exit
+ */
+ sop->so_rcvhigh = sop->so_rcvnext;
+ if (type == PT_SDP)
+ goto dopoll;
+ return;
+ }
+
+ /*
+ * This is a retransmitted PDU, so see if we have
+ * more in-sequence PDUs already queued up
+ */
+ while ((php = sop->so_recv_hd) &&
+ (php->ph_ns == sop->so_rcvnext)) {
+
+ /*
+ * Yup we do, so remove next PDU from queue and
+ * pass it up to the user as well
+ */
+ sop->so_recv_hd = php->ph_recv_lk;
+ if (sop->so_recv_hd == NULL)
+ sop->so_recv_tl = NULL;
+ STACK_CALL(SSCOP_DATA_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, (int)php->ph_buf, php->ph_ns,
+ err);
+ if (err) {
+ /*
+ * Should never happen, but...
+ */
+ KB_FREEALL(php->ph_buf);
+ sscop_abort(sop,
+ "sscop_sd_process: stack memory\n");
+ return;
+ }
+
+ /*
+ * Bump next expected sequence number
+ */
+ SEQ_INCR(sop->so_rcvnext, 1);
+
+ /*
+ * Slide receive window down
+ */
+ SEQ_INCR(sop->so_rcvmax, 1);
+ }
+
+ /*
+ * Finished with data...see if we need to poll
+ */
+ if (type == PT_SDP)
+ goto dopoll;
+ return;
+ }
+
+ /*
+ * We're gonna have to queue this PDU, so find space
+ * for the PDU header
+ */
+ KB_HEADROOM(m, space);
+
+ /*
+ * If there's not enough room in the received buffer,
+ * allocate & link a new buffer for the header
+ */
+ if (space < sizeof(struct pdu_hdr)) {
+
+ KB_ALLOC(n, sizeof(struct pdu_hdr), KB_F_NOWAIT, KB_T_HEADER);
+ if (n == NULL) {
+ KB_FREEALL(m);
+ return;
+ }
+ KB_HEADSET(n, sizeof(struct pdu_hdr));
+ KB_LEN(n) = 0;
+ KB_LINKHEAD(n, m);
+ m = n;
+ }
+
+ /*
+ * Build PDU header
+ *
+ * We can at least assume/require that the start of
+ * the user data is aligned. Also note that we don't
+ * include this header in the buffer len/offset fields.
+ */
+ KB_DATASTART(m, php, struct pdu_hdr *);
+ php--;
+ php->ph_ns = ns;
+ php->ph_buf = m;
+
+ /*
+ * Insert PDU into the receive queue
+ */
+ if (sscop_recv_insert(sop, php)) {
+ /*
+ * Oops, a duplicate sequence number PDU is already on
+ * the queue, somethings wrong here.
+ */
+ sscop_maa_error(sop, 'Q');
+
+ /*
+ * Free buffers
+ */
+ KB_FREEALL(m);
+
+ /*
+ * Reestablish a new connection
+ */
+ qsaal1_reestablish(sop);
+
+ return;
+ }
+
+ /*
+ * Are we at the high-water mark??
+ */
+ if (ns == sop->so_rcvhigh) {
+ /*
+ * Yes, just bump the mark
+ */
+ SEQ_INCR(sop->so_rcvhigh, 1);
+
+ if (type == PT_SDP)
+ goto dopoll;
+ return;
+ }
+
+ /*
+ * Are we beyond the high-water mark??
+ */
+ if (SEQ_GT(ns, sop->so_rcvhigh, sop->so_rcvnext)) {
+ /*
+ * Yes, then there's a missing PDU, so inform the transmitter
+ */
+ if (type == PT_SD)
+ (void) sscop_send_ustat(sop, ns);
+
+ /*
+ * Update high-water mark
+ */
+ sop->so_rcvhigh = SEQ_ADD(ns, 1);
+ }
+
+ if (type == PT_SD)
+ return;
+
+dopoll:
+ /*
+ * Do the "poll" part of an SDP PDU
+ */
+ poll.poll_nps = htonl(nps);
+ poll.poll_ns = htonl((PT_POLL << PT_TYPE_SHIFT) | ns);
+ sscop_poll_ready(sop, NULL, (caddr_t)&poll);
+ return;
+}
+
+
+/*
+ * SD PDU / SOS_READY Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_sd_ready(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ /*
+ * Just call common SD/SDP processor
+ */
+ sscop_sd_process(sop, m, trlr, PT_SD);
+
+ return;
+}
+
+
+/*
+ * SDP PDU / SOS_READY Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_sdp_ready(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ /*
+ * Just call common SD/SDP processor
+ */
+ sscop_sd_process(sop, m, trlr, PT_SDP);
+
+ return;
+}
+
+
+/*
+ * POLL PDU / SOS_INRESYN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_poll_inresyn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ int err;
+
+ /*
+ * Stop poll timer
+ */
+ sop->so_timer[SSCOP_T_POLL] = 0;
+ sop->so_flags &= ~SOF_KEEPALIVE;
+
+ /*
+ * Stop lost poll/stat timer
+ */
+ sop->so_timer[SSCOP_T_NORESP] = 0;
+
+ /*
+ * Report protocol error
+ */
+ sscop_poll_error(sop, m, trlr);
+
+ /*
+ * Return an END to peer
+ */
+ (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
+
+ /*
+ * Notify user of connection failure
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
+ if (err) {
+ sscop_abort(sop, "sscop_poll_inresyn: stack memory\n");
+ return;
+ }
+
+ /*
+ * Clear connection data
+ */
+ qsaal1_clear_connection(sop);
+
+ /*
+ * Back to idle state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * POLL PDU / SOS_CONRESYN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_poll_conresyn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ int err;
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Record error condition
+ */
+ sscop_poll_error(sop, m, trlr);
+
+ /*
+ * Return an END to peer
+ */
+ (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
+
+ /*
+ * Notify user of connection failure
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
+ if (err) {
+ sscop_abort(sop, "sscop_poll_conresyn: stack memory\n");
+ return;
+ }
+
+ /*
+ * Clear connection data
+ */
+ qsaal1_clear_connection(sop);
+
+ /*
+ * Go back to idle state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * POLL PDU / SOS_READY Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_poll_ready(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct poll_pdu *pp = (struct poll_pdu *)trlr;
+ sscop_seq nps;
+
+ NTOHL(pp->poll_ns);
+
+ /*
+ * If the poll sequence number is less than highest number
+ * we've already seen, something's wrong - so attempt to
+ * reestablish a new connection.
+ */
+ if (SEQ_LT(pp->poll_ns, sop->so_rcvhigh, sop->so_rcvnext)) {
+ /*
+ * Record error condition
+ */
+ sscop_maa_error(sop, 'Q');
+
+ /*
+ * Free buffers
+ */
+ KB_FREEALL(m);
+
+ /*
+ * Reestablish a new connection
+ */
+ qsaal1_reestablish(sop);
+
+ return;
+ }
+
+ /*
+ * Set a new "next highest" sequence number expected
+ */
+ if (SEQ_LT(pp->poll_ns, sop->so_rcvmax, sop->so_rcvnext))
+ SEQ_SET(sop->so_rcvhigh, pp->poll_ns);
+ else
+ sop->so_rcvhigh = sop->so_rcvmax;
+
+ /*
+ * Return a STAT PDU to peer
+ */
+ SEQ_SET(nps, ntohl(pp->poll_nps));
+ KB_FREEALL(m);
+ (void) sscop_send_stat(sop, nps);
+
+ return;
+}
+
+
+/*
+ * STAT PDU / SOS_CONRESYN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_stat_conresyn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ int err;
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Record error condition
+ */
+ sscop_stat_error(sop, m, trlr);
+
+ /*
+ * Return an END to peer
+ */
+ (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
+
+ /*
+ * Notify user of connection failure
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
+ if (err) {
+ sscop_abort(sop, "sscop_stat_conresyn: stack memory\n");
+ return;
+ }
+
+ /*
+ * Clear connection data
+ */
+ qsaal1_clear_connection(sop);
+
+ /*
+ * Go back to idle state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * USTAT PDU / SOS_CONRESYN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_ustat_conresyn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ int err;
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Record error condition
+ */
+ sscop_ustat_error(sop, m, trlr);
+
+ /*
+ * Return an END to peer
+ */
+ (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
+
+ /*
+ * Notify user of connection failure
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
+ if (err) {
+ sscop_abort(sop, "sscop_ustat_conresyn: stack memory\n");
+ return;
+ }
+
+ /*
+ * Clear connection data
+ */
+ qsaal1_clear_connection(sop);
+
+ /*
+ * Go back to idle state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
diff --git a/sys/netatm/uni/qsaal1_subr.c b/sys/netatm/uni/qsaal1_subr.c
new file mode 100644
index 0000000..ed4b43c
--- /dev/null
+++ b/sys/netatm/uni/qsaal1_subr.c
@@ -0,0 +1,206 @@
+/*
+ *
+ * ===================================
+ * 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: qsaal1_subr.c,v 1.6 1998/04/07 23:21:17 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * ITU-T Q.SAAL1 - Subroutines
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: qsaal1_subr.c,v 1.6 1998/04/07 23:21:17 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/uni.h>
+#include <netatm/uni/sscop.h>
+#include <netatm/uni/sscop_misc.h>
+#include <netatm/uni/sscop_pdu.h>
+#include <netatm/uni/sscop_var.h>
+
+
+/*
+ * Re-establish a new SSCOP Connection
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+qsaal1_reestablish(sop)
+ struct sscop *sop;
+{
+
+ /*
+ * Stop polling timers
+ */
+ sop->so_timer[SSCOP_T_POLL] = 0;
+ sop->so_timer[SSCOP_T_NORESP] = 0;
+ sop->so_flags &= ~SOF_KEEPALIVE;
+
+ /*
+ * Note that we're reestablishing a connection
+ */
+ sop->so_flags |= SOF_REESTAB;
+
+ /*
+ * Send first BGN PDU
+ */
+ sop->so_connctl = 1;
+ (void) sscop_send_bgn(sop, SSCOP_SOURCE_SSCOP);
+
+ /*
+ * Reset transmit variables
+ */
+ qsaal1_reset_xmit(sop);
+
+ /*
+ * Set retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc;
+
+ /*
+ * Wait for BGAK
+ */
+ sop->so_state = SOS_OUTCONN;
+
+ return;
+}
+
+
+/*
+ * Reset connection's transmitter state
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+qsaal1_reset_xmit(sop)
+ struct sscop *sop;
+{
+
+ /*
+ * Drain the transmission queues
+ */
+ sscop_xmit_drain(sop);
+
+ /*
+ * Reset transmit variables
+ */
+ SEQ_SET(sop->so_send, 0);
+ SEQ_SET(sop->so_pollsend, 0);
+ SEQ_SET(sop->so_ack, 0);
+ SEQ_SET(sop->so_pollack, 0);
+ if (sop->so_state != SOS_INCONN)
+ SEQ_SET(sop->so_sendmax, 0);
+ sop->so_polldata = 0;
+
+ return;
+}
+
+
+/*
+ * Reset connection's receiver state
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+qsaal1_reset_rcvr(sop)
+ struct sscop *sop;
+{
+
+ /*
+ * Drain the receiver queues
+ */
+ sscop_rcvr_drain(sop);
+
+ /*
+ * Reset transmit variables
+ */
+ SEQ_SET(sop->so_rcvnext, 0);
+ SEQ_SET(sop->so_rcvhigh, 0);
+ SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin);
+
+ return;
+}
+
+
+/*
+ * Clear connection's connection data
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+qsaal1_clear_connection(sop)
+ struct sscop *sop;
+{
+
+ /*
+ * Can we clear transmit buffers ??
+ */
+ if ((sop->so_flags & SOF_NOCLRBUF) == 0) {
+ /*
+ * Yes, drain the transmission queues
+ */
+ sscop_xmit_drain(sop);
+ }
+
+ /*
+ * Clear service required flag
+ */
+ sop->so_flags &= ~SOF_XMITSRVC;
+
+ /*
+ * Drain receive queue buffers
+ */
+ sscop_rcvr_drain(sop);
+
+ return;
+}
+
diff --git a/sys/netatm/uni/sscf_uni.c b/sys/netatm/uni/sscf_uni.c
new file mode 100644
index 0000000..b5fd7fb
--- /dev/null
+++ b/sys/netatm/uni/sscf_uni.c
@@ -0,0 +1,317 @@
+/*
+ *
+ * ===================================
+ * 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: sscf_uni.c,v 1.6 1998/03/24 21:10:38 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * Signalling AAL SSCF at the UNI
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: sscf_uni.c,v 1.6 1998/03/24 21:10:38 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/uni.h>
+#include <netatm/uni/sscop.h>
+#include <netatm/uni/sscf_uni.h>
+#include <netatm/uni/sscf_uni_var.h>
+
+
+/*
+ * Global variables
+ */
+int sscf_uni_vccnt = 0;
+
+/*
+ * Local functions
+ */
+static int sscf_uni_inst __P((struct stack_defn **, Atm_connvc *));
+
+/*
+ * Local variables
+ */
+static struct sp_info sscf_uni_pool = {
+ "sscf uni pool", /* si_name */
+ sizeof(struct univcc), /* si_blksiz */
+ 5, /* si_blkcnt */
+ 100 /* si_maxallow */
+};
+
+static struct stack_defn sscf_uni_service = {
+ NULL,
+ SAP_SSCF_UNI,
+ 0,
+ sscf_uni_inst,
+ sscf_uni_lower,
+ sscf_uni_upper,
+ 0
+};
+
+static struct t_atm_cause sscf_uni_cause = {
+ T_ATM_ITU_CODING,
+ T_ATM_LOC_USER,
+ T_ATM_CAUSE_TEMPORARY_FAILURE,
+ {0, 0, 0, 0}
+};
+
+
+/*
+ * Initialize SSCF UNI processing
+ *
+ * This will be called during module loading. We will register our stack
+ * service and wait for someone to talk to us.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 initialization was successful
+ * errno initialization failed - reason indicated
+ *
+ */
+int
+sscf_uni_start()
+{
+ int err = 0;
+
+ /*
+ * Register stack service
+ */
+ if (err = atm_stack_register(&sscf_uni_service))
+ goto done;
+
+done:
+ return (err);
+}
+
+
+/*
+ * Terminate SSCF UNI processing
+ *
+ * This will be called just prior to unloading the module from memory. All
+ * signalling instances should have been terminated by now, so we just free
+ * up all of our resources.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 termination was successful
+ * errno termination failed - reason indicated
+ *
+ */
+int
+sscf_uni_stop()
+{
+ /*
+ * Any connections still exist??
+ */
+ if (sscf_uni_vccnt) {
+
+ /*
+ * Yes, can't stop yet
+ */
+ return (EBUSY);
+ }
+
+ /*
+ * Deregister the stack service
+ */
+ (void) atm_stack_deregister(&sscf_uni_service);
+
+ /*
+ * Free our storage pools
+ */
+ atm_release_pool(&sscf_uni_pool);
+
+ return (0);
+}
+
+
+/*
+ * SSCF_UNI Stack Instantiation
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * ssp pointer to array of stack definition pointers for connection
+ * ssp[0] points to upper layer's stack service definition
+ * ssp[1] points to this layer's stack service definition
+ * ssp[2] points to lower layer's stack service definition
+ * cvp pointer to connection vcc for this stack
+ *
+ * Returns:
+ * 0 instantiation successful
+ * errno instantiation failed - reason indicated
+ *
+ */
+static int
+sscf_uni_inst(ssp, cvp)
+ struct stack_defn **ssp;
+ Atm_connvc *cvp;
+{
+ struct stack_defn *sdp_up = ssp[0],
+ *sdp_me = ssp[1],
+ *sdp_low = ssp[2];
+ struct univcc *uvp;
+ int err;
+
+ ATM_DEBUG2("sscf_uni_inst: ssp=0x%x, cvp=0x%x\n", ssp, cvp);
+
+ /*
+ * Validate lower SAP
+ */
+ if (sdp_low->sd_sap != SAP_SSCOP)
+ return (EINVAL);
+
+ /*
+ * Allocate our control block
+ */
+ uvp = (struct univcc *)atm_allocate(&sscf_uni_pool);
+ if (uvp == NULL)
+ return (ENOMEM);
+
+ uvp->uv_ustate = UVU_INST;
+ uvp->uv_lstate = UVL_INST;
+ uvp->uv_connvc = cvp;
+ uvp->uv_toku = sdp_up->sd_toku;
+ uvp->uv_upper = sdp_up->sd_upper;
+ sscf_uni_vccnt++;
+
+ /*
+ * Store my token into service definition
+ */
+ sdp_me->sd_toku = uvp;
+
+ /*
+ * Update and save input buffer headroom
+ */
+ HEADIN(cvp, 0, 0);
+ /* uvp->uv_headin = cvp->cvc_attr.headin; */
+
+ /*
+ * Pass instantiation down the stack
+ */
+ err = sdp_low->sd_inst(ssp + 1, cvp);
+ if (err) {
+ /*
+ * Lower layer instantiation failed, free our resources
+ */
+ atm_free((caddr_t)uvp);
+ sscf_uni_vccnt--;
+ return (err);
+ }
+
+ /*
+ * Save and update output buffer headroom
+ */
+ /* uvp->uv_headout = cvp->cvc_attr.headout; */
+ HEADOUT(cvp, 0, 0);
+
+ /*
+ * Save lower layer's interface info
+ */
+ uvp->uv_lower = sdp_low->sd_lower;
+ uvp->uv_tokl = sdp_low->sd_toku;
+
+ return (0);
+}
+
+
+/*
+ * Abort an SSCF_UNI connection
+ *
+ * Called when an unrecoverable or "should never happen" error occurs.
+ * We just log a message and request the signalling manager to abort the
+ * connection.
+ *
+ * Arguments:
+ * uvp pointer to univcc control block
+ * msg pointer to error message
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscf_uni_abort(uvp, msg)
+ struct univcc *uvp;
+ char *msg;
+{
+ /*
+ * Log error message
+ */
+ log(LOG_ERR, msg);
+
+ /*
+ * Set termination states
+ */
+ uvp->uv_ustate = UVU_TERM;
+ uvp->uv_lstate = UVL_TERM;
+
+ /*
+ * Tell Connection Manager to abort this connection
+ */
+ (void) atm_cm_abort(uvp->uv_connvc, &sscf_uni_cause);
+}
+
+
+/*
+ * Print an SSCF PDU
+ *
+ * Arguments:
+ * uvp pointer to univcc control block
+ * m pointer to pdu buffer chain
+ * msg pointer to message string
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscf_uni_pdu_print(uvp, m, msg)
+ struct univcc *uvp;
+ KBuffer *m;
+ char *msg;
+{
+ char buf[128];
+ struct vccb *vcp;
+
+ vcp = uvp->uv_connvc->cvc_vcc;
+ sprintf(buf, "sscf_uni %s: vcc=(%d,%d)\n",
+ msg, vcp->vc_vpi, vcp->vc_vci);
+ atm_pdu_print(m, buf);
+}
+
diff --git a/sys/netatm/uni/sscf_uni.h b/sys/netatm/uni/sscf_uni.h
new file mode 100644
index 0000000..cf24446
--- /dev/null
+++ b/sys/netatm/uni/sscf_uni.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * ===================================
+ * 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: sscf_uni.h,v 1.2 1997/05/06 22:19:34 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * SSCF UNI protocol definitions
+ *
+ */
+
+#ifndef _UNI_SSCF_UNI_H
+#define _UNI_SSCF_UNI_H
+
+/*
+ * SSCF_UNI API definitions
+ */
+#define SSCF_UNI_ESTIND_YES 1 /* Allow new ESTABLISH_IND */
+#define SSCF_UNI_ESTIND_NO 2 /* Disallow new ESTABLISH_IND */
+
+#endif /* _UNI_SSCF_UNI_H */
diff --git a/sys/netatm/uni/sscf_uni_lower.c b/sys/netatm/uni/sscf_uni_lower.c
new file mode 100644
index 0000000..fe2d839
--- /dev/null
+++ b/sys/netatm/uni/sscf_uni_lower.c
@@ -0,0 +1,379 @@
+/*
+ *
+ * ===================================
+ * 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: sscf_uni_lower.c,v 1.6 1998/04/07 23:23:26 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * SSCF UNI - SSCF_UNI SAP interface processing
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: sscf_uni_lower.c,v 1.6 1998/04/07 23:23:26 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/uni.h>
+#include <netatm/uni/sscop.h>
+#include <netatm/uni/sscf_uni.h>
+#include <netatm/uni/sscf_uni_var.h>
+
+
+/*
+ * Local variables
+ */
+static struct sscop_parms sscf_uni_sscop_parms = {
+ 4096, /* sp_maxinfo */
+ 4096, /* sp_maxuu */
+ 4, /* sp_maxcc */
+ 25, /* sp_maxpd */
+ 1 * ATM_HZ, /* sp_timecc */
+ 2 * ATM_HZ, /* sp_timekeep */
+ 7 * ATM_HZ, /* sp_timeresp */
+ 1 * ATM_HZ, /* sp_timepoll */
+ 15 * ATM_HZ, /* sp_timeidle */
+ 80 /* sp_rcvwin */
+};
+
+
+/*
+ * SSCF_UNI Lower Stack Command Handler
+ *
+ * This function will receive all of the stack commands issued from the
+ * layer above SSCF UNI (ie. Q.2931).
+ *
+ * Arguments:
+ * cmd stack command code
+ * tok session token
+ * arg1 command specific argument
+ * arg2 command specific argument
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscf_uni_lower(cmd, tok, arg1, arg2)
+ int cmd;
+ void *tok;
+ int arg1;
+ int arg2;
+{
+ struct univcc *uvp = (struct univcc *)tok;
+ Atm_connvc *cvp = uvp->uv_connvc;
+ enum sscop_vers vers;
+ int err;
+
+ ATM_DEBUG5("sscf_uni_lower: cmd=0x%x, uvp=0x%x, ustate=%d, arg1=0x%x, arg2=0x%x\n",
+ cmd, (int)uvp, uvp->uv_ustate, arg1, arg2);
+
+ switch (cmd) {
+
+ case SSCF_UNI_INIT:
+ /*
+ * Validate state
+ */
+ if (uvp->uv_ustate != UVU_INST) {
+ log(LOG_ERR, "sscf_uni_lower: SSCF_INIT in ustate=%d\n",
+ uvp->uv_ustate);
+ sscf_uni_abort(uvp, "sscf_uni: sequence err\n");
+ break;
+ }
+
+ /*
+ * Validate UNI version
+ */
+ if ((enum uni_vers)arg1 == UNI_VERS_3_0)
+ vers = SSCOP_VERS_QSAAL;
+ else if ((enum uni_vers)arg1 == UNI_VERS_3_1)
+ vers = SSCOP_VERS_Q2110;
+ else {
+ sscf_uni_abort(uvp, "sscf_uni: bad version\n");
+ break;
+ }
+ uvp->uv_vers = (enum uni_vers)arg1;
+
+ /*
+ * Make ourselves ready and pass on the INIT
+ */
+ uvp->uv_ustate = UVU_RELEASED;
+ uvp->uv_lstate = UVL_IDLE;
+
+ STACK_CALL(SSCOP_INIT, uvp->uv_lower, uvp->uv_tokl, cvp,
+ (int)vers, (int)&sscf_uni_sscop_parms, err);
+ if (err) {
+ /*
+ * Should never happen
+ */
+ sscf_uni_abort(uvp, "sscf_uni: INIT failure\n");
+ }
+ break;
+
+ case SSCF_UNI_TERM:
+ /*
+ * Set termination states
+ */
+ uvp->uv_ustate = UVU_TERM;
+ uvp->uv_lstate = UVL_TERM;
+
+ /*
+ * Pass the TERM down the stack
+ */
+ STACK_CALL(SSCOP_TERM, uvp->uv_lower, uvp->uv_tokl, cvp,
+ 0, 0, err);
+ if (err) {
+ /*
+ * Should never happen
+ */
+ sscf_uni_abort(uvp, "sscf_uni: TERM failure\n");
+ return;
+ }
+ atm_free((caddr_t)uvp);
+ sscf_uni_vccnt--;
+ break;
+
+ case SSCF_UNI_ESTABLISH_REQ:
+ /*
+ * Validation based on user state
+ */
+ switch (uvp->uv_ustate) {
+
+ case UVU_RELEASED:
+ case UVU_PRELEASE:
+ /*
+ * Establishing a new connection
+ */
+ uvp->uv_ustate = UVU_PACTIVE;
+ uvp->uv_lstate = UVL_OUTCONN;
+ STACK_CALL(SSCOP_ESTABLISH_REQ, uvp->uv_lower,
+ uvp->uv_tokl, cvp,
+ SSCOP_UU_NULL, SSCOP_BR_YES, err);
+ if (err) {
+ sscf_uni_abort(uvp, "sscf_uni: stack memory\n");
+ return;
+ }
+ break;
+
+ case UVU_ACTIVE:
+ /*
+ * Resynchronizing a connection
+ */
+ uvp->uv_ustate = UVU_PACTIVE;
+ if (uvp->uv_vers == UNI_VERS_3_0) {
+ uvp->uv_lstate = UVL_OUTCONN;
+ STACK_CALL(SSCOP_ESTABLISH_REQ, uvp->uv_lower,
+ uvp->uv_tokl, cvp,
+ SSCOP_UU_NULL, SSCOP_BR_YES, err);
+ } else {
+ uvp->uv_lstate = UVL_OUTRESYN;
+ STACK_CALL(SSCOP_RESYNC_REQ, uvp->uv_lower,
+ uvp->uv_tokl, cvp,
+ SSCOP_UU_NULL, 0, err);
+ }
+ if (err) {
+ sscf_uni_abort(uvp, "sscf_uni: stack memory\n");
+ return;
+ }
+ break;
+
+ case UVU_TERM:
+ /* Ignore */
+ break;
+
+ case UVU_INST:
+ case UVU_PACTIVE:
+ default:
+ log(LOG_ERR, "sscf_uni_lower: cmd=0x%x, ustate=%d\n",
+ cmd, uvp->uv_ustate);
+ sscf_uni_abort(uvp, "sscf_uni: sequence err\n");
+ }
+ break;
+
+ case SSCF_UNI_RELEASE_REQ:
+ /*
+ * Validate re-establishment parameter
+ */
+ switch (arg1) {
+
+ case SSCF_UNI_ESTIND_YES:
+ uvp->uv_flags &= ~UVF_NOESTIND;
+ break;
+
+ case SSCF_UNI_ESTIND_NO:
+ uvp->uv_flags |= UVF_NOESTIND;
+ break;
+
+ default:
+ sscf_uni_abort(uvp, "sscf_uni: bad estind value\n");
+ return;
+ }
+
+ /*
+ * Validation based on user state
+ */
+ switch (uvp->uv_ustate) {
+
+ case UVU_RELEASED:
+ /*
+ * Releasing a non-existant connection
+ */
+ STACK_CALL(SSCF_UNI_RELEASE_CNF, uvp->uv_upper,
+ uvp->uv_toku, cvp,
+ 0, 0, err);
+ if (err) {
+ sscf_uni_abort(uvp, "sscf_uni: stack memory\n");
+ return;
+ }
+ break;
+
+ case UVU_PACTIVE:
+ case UVU_ACTIVE:
+ /*
+ * Releasing a connection
+ */
+ uvp->uv_ustate = UVU_PRELEASE;
+ uvp->uv_lstate = UVL_OUTDISC;
+ STACK_CALL(SSCOP_RELEASE_REQ, uvp->uv_lower,
+ uvp->uv_tokl, cvp,
+ SSCOP_UU_NULL, 0, err);
+ if (err) {
+ sscf_uni_abort(uvp, "sscf_uni: stack memory\n");
+ return;
+ }
+ break;
+
+ case UVU_TERM:
+ /* Ignore */
+ break;
+
+ case UVU_INST:
+ case UVU_PRELEASE:
+ default:
+ log(LOG_ERR, "sscf_uni_lower: cmd=0x%x, ustate=%d\n",
+ cmd, uvp->uv_ustate);
+ sscf_uni_abort(uvp, "sscf_uni: sequence err\n");
+ }
+ break;
+
+ case SSCF_UNI_DATA_REQ:
+#ifdef notdef
+ sscf_uni_pdu_print(uvp, (KBuffer *)arg1, "DATA_REQ");
+#endif
+
+ /*
+ * Validation based on user state
+ */
+ switch (uvp->uv_ustate) {
+
+ case UVU_ACTIVE:
+ /*
+ * Send assured data on connection
+ */
+ STACK_CALL(SSCOP_DATA_REQ, uvp->uv_lower,
+ uvp->uv_tokl, cvp,
+ arg1, 0, err);
+ if (err) {
+ KB_FREEALL((KBuffer *)arg1);
+ sscf_uni_abort(uvp, "sscf_uni: stack memory\n");
+ return;
+ }
+ break;
+
+ case UVU_RELEASED:
+ case UVU_TERM:
+ /*
+ * Release supplied buffers and ignore
+ */
+ KB_FREEALL((KBuffer *)arg1);
+ break;
+
+ case UVU_INST:
+ case UVU_PACTIVE:
+ case UVU_PRELEASE:
+ default:
+ KB_FREEALL((KBuffer *)arg1);
+ log(LOG_ERR, "sscf_uni_lower: cmd=0x%x, ustate=%d\n",
+ cmd, uvp->uv_ustate);
+ sscf_uni_abort(uvp, "sscf_uni: sequence err\n");
+ }
+ break;
+
+ case SSCF_UNI_UNITDATA_REQ:
+#ifdef notdef
+ sscf_uni_pdu_print(uvp, (KBuffer *)arg1, "UNITDATA_REQ");
+#endif
+
+ /*
+ * Validation based on user state
+ */
+ switch (uvp->uv_ustate) {
+
+ case UVU_RELEASED:
+ case UVU_PACTIVE:
+ case UVU_PRELEASE:
+ case UVU_ACTIVE:
+ /*
+ * Send unassured data on connection
+ */
+ STACK_CALL(SSCOP_UNITDATA_REQ, uvp->uv_lower,
+ uvp->uv_tokl, cvp,
+ arg1, 0, err);
+ if (err) {
+ KB_FREEALL((KBuffer *)arg1);
+ sscf_uni_abort(uvp, "sscf_uni: stack memory\n");
+ return;
+ }
+ break;
+
+ case UVU_TERM:
+ /*
+ * Release supplied buffers and ignore
+ */
+ KB_FREEALL((KBuffer *)arg1);
+ break;
+
+ case UVU_INST:
+ default:
+ KB_FREEALL((KBuffer *)arg1);
+ log(LOG_ERR, "sscf_uni_lower: cmd=0x%x, ustate=%d\n",
+ cmd, uvp->uv_ustate);
+ sscf_uni_abort(uvp, "sscf_uni: sequence err\n");
+ }
+ break;
+
+ default:
+ log(LOG_ERR, "sscf_uni_lower: unknown cmd 0x%x, uvp=0x%x\n",
+ cmd, (int)uvp);
+ }
+
+ return;
+}
+
diff --git a/sys/netatm/uni/sscf_uni_upper.c b/sys/netatm/uni/sscf_uni_upper.c
new file mode 100644
index 0000000..2febb5c
--- /dev/null
+++ b/sys/netatm/uni/sscf_uni_upper.c
@@ -0,0 +1,625 @@
+/*
+ *
+ * ===================================
+ * 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: sscf_uni_upper.c,v 1.7 1998/06/29 22:15:31 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * SSCF UNI - SSCOP SAP interface processing
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: sscf_uni_upper.c,v 1.7 1998/06/29 22:15:31 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/uni.h>
+#include <netatm/uni/sscop.h>
+#include <netatm/uni/sscf_uni.h>
+#include <netatm/uni/sscf_uni_var.h>
+
+
+/*
+ * SSCF_UNI Upper Stack Command Handler
+ *
+ * This function will receive all of the stack commands issued from the
+ * layer below SSCF UNI (ie. SSCOP).
+ *
+ * Arguments:
+ * cmd stack command code
+ * tok session token
+ * arg1 command specific argument
+ * arg2 command specific argument
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscf_uni_upper(cmd, tok, arg1, arg2)
+ int cmd;
+ void *tok;
+ int arg1;
+ int arg2;
+{
+ struct univcc *uvp = (struct univcc *)tok;
+ Atm_connvc *cvp = uvp->uv_connvc;
+ int err;
+
+ ATM_DEBUG5("sscf_uni_upper: cmd=0x%x, uvp=0x%x, lstate=%d, arg1=0x%x, arg2=0x%x\n",
+ cmd, (int)uvp, uvp->uv_lstate, arg1, arg2);
+
+ switch (cmd) {
+
+ case SSCOP_ESTABLISH_IND:
+ /*
+ * We don't support SSCOP User-to-User data, so just
+ * get rid of any supplied to us
+ */
+ if (arg1 != SSCOP_UU_NULL)
+ KB_FREEALL((KBuffer *)arg1);
+
+ /*
+ * Validation based on sscop state
+ */
+ switch (uvp->uv_lstate) {
+
+ case UVL_READY:
+ if (uvp->uv_vers != UNI_VERS_3_0) {
+ goto seqerr;
+ }
+ goto doestind;
+
+ case UVL_IDLE:
+ /*
+ * Incoming connection establishment request
+ */
+
+ /*
+ * If user doesn't want any more incoming sessions
+ * accepted, then refuse request
+ */
+ if (uvp->uv_flags & UVF_NOESTIND) {
+ STACK_CALL(SSCOP_RELEASE_REQ, uvp->uv_lower,
+ uvp->uv_tokl, cvp,
+ SSCOP_UU_NULL, 0, err);
+ if (err) {
+ sscf_uni_abort(uvp,
+ "sscf_uni: stack memory\n");
+ return;
+ }
+ break;
+ }
+
+doestind:
+ /*
+ * Tell sscop we've accepted the new connection
+ */
+ uvp->uv_lstate = UVL_READY;
+ STACK_CALL(SSCOP_ESTABLISH_RSP, uvp->uv_lower,
+ uvp->uv_tokl, cvp,
+ SSCOP_UU_NULL, SSCOP_BR_YES, err);
+ if (err) {
+ sscf_uni_abort(uvp, "sscf_uni: stack memory\n");
+ return;
+ }
+
+ /*
+ * Now notify the user of the new connection
+ */
+ uvp->uv_ustate = UVU_ACTIVE;
+ STACK_CALL(SSCF_UNI_ESTABLISH_IND, uvp->uv_upper,
+ uvp->uv_toku, cvp,
+ SSCOP_UU_NULL, 0, err);
+ if (err) {
+ sscf_uni_abort(uvp, "sscf_uni: stack memory\n");
+ return;
+ }
+ break;
+
+ case UVL_TERM:
+ /*
+ * Ignoring everything
+ */
+ break;
+
+ case UVL_INST:
+ case UVL_OUTCONN:
+ case UVL_INCONN:
+ case UVL_OUTDISC:
+ case UVL_OUTRESYN:
+ case UVL_INRESYN:
+ case UVL_RECOVERY:
+ default:
+seqerr:
+ log(LOG_ERR, "sscf_uni_upper: cmd=0x%x, lstate=%d\n",
+ cmd, uvp->uv_lstate);
+ sscf_uni_abort(uvp, "sscf_uni: sequence err\n");
+ }
+ break;
+
+ case SSCOP_ESTABLISH_CNF:
+ /*
+ * We don't support SSCOP User-to-User data, so just
+ * get rid of any supplied to us
+ */
+ if (arg1 != SSCOP_UU_NULL)
+ KB_FREEALL((KBuffer *)arg1);
+
+ /*
+ * Validation based on sscop state
+ */
+ switch (uvp->uv_lstate) {
+
+ case UVL_OUTCONN:
+ /*
+ * Outgoing connection establishment completed
+ */
+
+ /*
+ * Tell the user that the connection is established
+ */
+ uvp->uv_ustate = UVU_ACTIVE;
+ uvp->uv_lstate = UVL_READY;
+ STACK_CALL(SSCF_UNI_ESTABLISH_CNF, uvp->uv_upper,
+ uvp->uv_toku, cvp,
+ SSCOP_UU_NULL, 0, err);
+ if (err) {
+ sscf_uni_abort(uvp, "sscf_uni: stack memory\n");
+ return;
+ }
+ break;
+
+ case UVL_TERM:
+ /*
+ * Ignoring everything
+ */
+ break;
+
+ case UVL_INST:
+ case UVL_IDLE:
+ case UVL_INCONN:
+ case UVL_OUTDISC:
+ case UVL_OUTRESYN:
+ case UVL_INRESYN:
+ case UVL_RECOVERY:
+ case UVL_READY:
+ default:
+ log(LOG_ERR, "sscf_uni_upper: cmd=0x%x, lstate=%d\n",
+ cmd, uvp->uv_lstate);
+ sscf_uni_abort(uvp, "sscf_uni: sequence err\n");
+ }
+ break;
+
+ case SSCOP_RELEASE_IND:
+ /*
+ * We don't support SSCOP User-to-User data, so just
+ * get rid of any supplied to us
+ */
+ if (arg1 != SSCOP_UU_NULL)
+ KB_FREEALL((KBuffer *)arg1);
+
+ /*
+ * Validation based on sscop state
+ */
+ switch (uvp->uv_lstate) {
+
+ case UVL_OUTCONN:
+ case UVL_OUTRESYN:
+ case UVL_READY:
+ /*
+ * Peer requesting connection termination
+ */
+
+ /*
+ * Notify the user that the connection
+ * has been terminated
+ */
+ uvp->uv_ustate = UVU_RELEASED;
+ uvp->uv_lstate = UVL_IDLE;
+ STACK_CALL(SSCF_UNI_RELEASE_IND, uvp->uv_upper,
+ uvp->uv_toku, cvp,
+ SSCOP_UU_NULL, 0, err);
+ if (err) {
+ sscf_uni_abort(uvp, "sscf_uni: stack memory\n");
+ return;
+ }
+ break;
+
+ case UVL_TERM:
+ /*
+ * Ignoring everything
+ */
+ break;
+
+ case UVL_INST:
+ case UVL_IDLE:
+ case UVL_INCONN:
+ case UVL_OUTDISC:
+ case UVL_INRESYN:
+ case UVL_RECOVERY:
+ default:
+ log(LOG_ERR, "sscf_uni_upper: cmd=0x%x, lstate=%d\n",
+ cmd, uvp->uv_lstate);
+ sscf_uni_abort(uvp, "sscf_uni: sequence err\n");
+ }
+ break;
+
+ case SSCOP_RELEASE_CNF:
+ /*
+ * Validation based on sscop state
+ */
+ switch (uvp->uv_lstate) {
+
+ case UVL_OUTDISC:
+ /*
+ * Peer acknowledging connection termination
+ */
+
+ /*
+ * Notify the user that the connection
+ * termination is completed
+ */
+ uvp->uv_ustate = UVU_RELEASED;
+ uvp->uv_lstate = UVL_IDLE;
+ STACK_CALL(SSCF_UNI_RELEASE_CNF, uvp->uv_upper,
+ uvp->uv_toku, cvp,
+ SSCOP_UU_NULL, 0, err);
+ if (err) {
+ sscf_uni_abort(uvp, "sscf_uni: stack memory\n");
+ return;
+ }
+ break;
+
+ case UVL_TERM:
+ /*
+ * Ignoring everything
+ */
+ break;
+
+ case UVL_INST:
+ case UVL_IDLE:
+ case UVL_OUTCONN:
+ case UVL_INCONN:
+ case UVL_OUTRESYN:
+ case UVL_INRESYN:
+ case UVL_RECOVERY:
+ case UVL_READY:
+ default:
+ log(LOG_ERR, "sscf_uni_upper: cmd=0x%x, lstate=%d\n",
+ cmd, uvp->uv_lstate);
+ sscf_uni_abort(uvp, "sscf_uni: sequence err\n");
+ }
+ break;
+
+ case SSCOP_DATA_IND:
+#ifdef notdef
+ sscf_uni_pdu_print(uvp, (KBuffer *)arg1, "DATA_IND");
+#endif
+
+ /*
+ * Validation based on sscop state
+ */
+ switch (uvp->uv_lstate) {
+
+ case UVL_READY:
+ /*
+ * Incoming assured data from peer
+ */
+
+ /*
+ * Pass the data up to the user
+ */
+ STACK_CALL(SSCF_UNI_DATA_IND, uvp->uv_upper,
+ uvp->uv_toku, cvp,
+ arg1, 0, err);
+ if (err) {
+ KB_FREEALL((KBuffer *)arg1);
+ sscf_uni_abort(uvp, "sscf_uni: stack memory\n");
+ return;
+ }
+ break;
+
+ case UVL_TERM:
+ /*
+ * Ignoring everything
+ */
+ KB_FREEALL((KBuffer *)arg1);
+ break;
+
+ case UVL_INST:
+ case UVL_IDLE:
+ case UVL_OUTCONN:
+ case UVL_INCONN:
+ case UVL_OUTDISC:
+ case UVL_OUTRESYN:
+ case UVL_INRESYN:
+ case UVL_RECOVERY:
+ default:
+ KB_FREEALL((KBuffer *)arg1);
+ log(LOG_ERR, "sscf_uni_upper: cmd=0x%x, lstate=%d\n",
+ cmd, uvp->uv_lstate);
+ sscf_uni_abort(uvp, "sscf_uni: sequence err\n");
+ }
+ break;
+
+ case SSCOP_RESYNC_IND:
+ /*
+ * We don't support SSCOP User-to-User data, so just
+ * get rid of any supplied to us
+ */
+ if (arg1 != SSCOP_UU_NULL)
+ KB_FREEALL((KBuffer *)arg1);
+
+ /*
+ * Validation based on sscop state
+ */
+ switch (uvp->uv_lstate) {
+
+ case UVL_READY:
+ /*
+ * Incoming connection resynchronization request
+ */
+
+ /*
+ * Send resynch acknowledgement to sscop
+ */
+ STACK_CALL(SSCOP_RESYNC_RSP, uvp->uv_lower,
+ uvp->uv_tokl, cvp,
+ 0, 0, err);
+ if (err) {
+ sscf_uni_abort(uvp, "sscf_uni: stack memory\n");
+ return;
+ }
+
+ if (uvp->uv_vers != UNI_VERS_3_0) {
+
+ /*
+ * Notify the user that the connection
+ * has been resynced
+ */
+ STACK_CALL(SSCF_UNI_ESTABLISH_IND,
+ uvp->uv_upper, uvp->uv_toku, cvp,
+ SSCOP_UU_NULL, 0, err);
+ if (err) {
+ sscf_uni_abort(uvp,
+ "sscf_uni: stack memory\n");
+ return;
+ }
+ }
+ break;
+
+ case UVL_TERM:
+ /*
+ * Ignoring everything
+ */
+ break;
+
+ case UVL_INST:
+ case UVL_IDLE:
+ case UVL_OUTCONN:
+ case UVL_INCONN:
+ case UVL_OUTDISC:
+ case UVL_OUTRESYN:
+ case UVL_INRESYN:
+ case UVL_RECOVERY:
+ default:
+ log(LOG_ERR, "sscf_uni_upper: cmd=0x%x, lstate=%d\n",
+ cmd, uvp->uv_lstate);
+ sscf_uni_abort(uvp, "sscf_uni: sequence err\n");
+ }
+ break;
+
+ case SSCOP_RESYNC_CNF:
+ /*
+ * Not supported in version 3.0
+ */
+ if (uvp->uv_vers == UNI_VERS_3_0) {
+ sscf_uni_abort(uvp,
+ "sscf_uni: SSCOP_RESYNC_CNF in 3.0\n");
+ return;
+ }
+
+ /*
+ * Validation based on sscop state
+ */
+ switch (uvp->uv_lstate) {
+
+ case UVL_OUTRESYN:
+ /*
+ * Peer acknowledging connection resynchronization
+ */
+
+ /*
+ * Now notify the user that the connection
+ * has been resynced
+ */
+ uvp->uv_ustate = UVU_ACTIVE;
+ uvp->uv_lstate = UVL_READY;
+ STACK_CALL(SSCF_UNI_ESTABLISH_CNF, uvp->uv_upper,
+ uvp->uv_toku, cvp,
+ SSCOP_UU_NULL, 0, err);
+ if (err) {
+ sscf_uni_abort(uvp, "sscf_uni: stack memory\n");
+ return;
+ }
+ break;
+
+ case UVL_TERM:
+ /*
+ * Ignoring everything
+ */
+ break;
+
+ case UVL_INST:
+ case UVL_IDLE:
+ case UVL_OUTCONN:
+ case UVL_INCONN:
+ case UVL_OUTDISC:
+ case UVL_INRESYN:
+ case UVL_RECOVERY:
+ case UVL_READY:
+ default:
+ log(LOG_ERR, "sscf_uni_upper: cmd=0x%x, lstate=%d\n",
+ cmd, uvp->uv_lstate);
+ sscf_uni_abort(uvp, "sscf_uni: sequence err\n");
+ }
+ break;
+
+ case SSCOP_RECOVER_IND:
+ /*
+ * Not supported in version 3.0
+ */
+ if (uvp->uv_vers == UNI_VERS_3_0) {
+ sscf_uni_abort(uvp,
+ "sscf_uni: SSCOP_RECOVER_IND in 3.0\n");
+ return;
+ }
+
+ /*
+ * Validation based on sscop state
+ */
+ switch (uvp->uv_lstate) {
+
+ case UVL_READY:
+ /*
+ * Recover connection due to internal problems
+ */
+
+ /*
+ * Send recovery acknowledgement to sscop
+ */
+ STACK_CALL(SSCOP_RECOVER_RSP, uvp->uv_lower,
+ uvp->uv_tokl, cvp,
+ 0, 0, err);
+ if (err) {
+ sscf_uni_abort(uvp, "sscf_uni: stack memory\n");
+ return;
+ }
+
+ /*
+ * Now notify the user that the connection
+ * has been recovered
+ */
+ STACK_CALL(SSCF_UNI_ESTABLISH_IND, uvp->uv_upper,
+ uvp->uv_toku, cvp,
+ SSCOP_UU_NULL, 0, err);
+ if (err) {
+ sscf_uni_abort(uvp, "sscf_uni: stack memory\n");
+ return;
+ }
+ break;
+
+ case UVL_TERM:
+ /*
+ * Ignoring everything
+ */
+ break;
+
+ case UVL_INST:
+ case UVL_IDLE:
+ case UVL_OUTCONN:
+ case UVL_INCONN:
+ case UVL_OUTDISC:
+ case UVL_OUTRESYN:
+ case UVL_INRESYN:
+ case UVL_RECOVERY:
+ default:
+ log(LOG_ERR, "sscf_uni_upper: cmd=0x%x, lstate=%d\n",
+ cmd, uvp->uv_lstate);
+ sscf_uni_abort(uvp, "sscf_uni: sequence err\n");
+ }
+ break;
+
+ case SSCOP_UNITDATA_IND:
+#ifdef notdef
+ sscf_uni_pdu_print(uvp, (KBuffer *)arg1, "UNITDATA_IND");
+#endif
+
+ /*
+ * Validation based on sscop state
+ */
+ switch (uvp->uv_lstate) {
+
+ case UVL_IDLE:
+ case UVL_OUTCONN:
+ case UVL_INCONN:
+ case UVL_OUTDISC:
+ case UVL_OUTRESYN:
+ case UVL_INRESYN:
+ case UVL_RECOVERY:
+ case UVL_READY:
+ /*
+ * Incoming unassured data from peer
+ */
+
+ /*
+ * Pass the data up to the user
+ */
+ STACK_CALL(SSCF_UNI_UNITDATA_IND, uvp->uv_upper,
+ uvp->uv_toku, cvp,
+ arg1, 0, err);
+ if (err) {
+ KB_FREEALL((KBuffer *)arg1);
+ sscf_uni_abort(uvp, "sscf_uni: stack memory\n");
+ return;
+ }
+ break;
+
+ case UVL_TERM:
+ /*
+ * Ignoring everything
+ */
+ KB_FREEALL((KBuffer *)arg1);
+ break;
+
+ case UVL_INST:
+ default:
+ KB_FREEALL((KBuffer *)arg1);
+ log(LOG_ERR, "sscf_uni_upper: cmd=0x%x, lstate=%d\n",
+ cmd, uvp->uv_lstate);
+ sscf_uni_abort(uvp, "sscf_uni: sequence err\n");
+ }
+ break;
+
+ case SSCOP_RETRIEVE_IND:
+ case SSCOP_RETRIEVECMP_IND:
+ /*
+ * Not supported
+ */
+ default:
+ log(LOG_ERR, "sscf_uni_upper: unknown cmd 0x%x, uvp=0x%x\n",
+ cmd, (int)uvp);
+ }
+
+ return;
+}
+
diff --git a/sys/netatm/uni/sscf_uni_var.h b/sys/netatm/uni/sscf_uni_var.h
new file mode 100644
index 0000000..ffed7de
--- /dev/null
+++ b/sys/netatm/uni/sscf_uni_var.h
@@ -0,0 +1,115 @@
+/*
+ *
+ * ===================================
+ * 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: sscf_uni_var.h,v 1.5 1998/02/19 20:22:05 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * SSCF UNI protocol control blocks
+ *
+ */
+
+#ifndef _UNI_SSCF_UNI_VAR_H
+#define _UNI_SSCF_UNI_VAR_H
+
+/*
+ * Structure containing information for each SSCF UNI connection.
+ */
+struct univcc {
+ u_char uv_ustate; /* SSCF-User state (see below) */
+ u_char uv_lstate; /* SSCF-SSCOP state (see below) */
+ u_short uv_flags; /* Connection flags (see below) */
+ enum uni_vers uv_vers; /* UNI version */
+
+ /* Stack variables */
+ Atm_connvc *uv_connvc; /* Connection vcc for this stack */
+ void *uv_toku; /* Stack upper layer's token */
+ void *uv_tokl; /* Stack lower layer's token */
+ void (*uv_upper) /* Stack upper layer's interface */
+ __P((int, void *, int, int));
+ void (*uv_lower) /* Stack lower layer's interface */
+ __P((int, void *, int, int));
+};
+
+/*
+ * SSCF to SAAL User (Q.2931) Interface States
+ */
+#define UVU_INST 0 /* Instantiated, waiting for INIT */
+#define UVU_RELEASED 1 /* Connection released */
+#define UVU_PACTIVE 2 /* Awaiting connection establishment */
+#define UVU_PRELEASE 3 /* Awaiting connection release */
+#define UVU_ACTIVE 4 /* Connection established */
+#define UVU_TERM 5 /* Waiting for TERM */
+
+/*
+ * SSCF to SSCOP Interface States
+ */
+#define UVL_INST 0 /* Instantiated, waiting for INIT */
+#define UVL_IDLE 1 /* Idle */
+#define UVL_OUTCONN 2 /* Outgoing connection pending */
+#define UVL_INCONN 3 /* Incoming connection pending */
+#define UVL_OUTDISC 4 /* Outgoing disconnection pending */
+#define UVL_OUTRESYN 5 /* Outgoing resynchronization pending */
+#define UVL_INRESYN 6 /* Incoming resynchornization pending */
+#define UVL_RECOVERY 8 /* Recovery pending */
+#define UVL_READY 10 /* Data transfer ready */
+#define UVL_TERM 11 /* Waiting for TERM */
+
+/*
+ * Connection Flags
+ */
+#define UVF_NOESTIND 0x0001 /* Don't process ESTABLISH_IND */
+
+
+#ifdef ATM_KERNEL
+/*
+ * Global function declarations
+ */
+ /* sscf_uni.c */
+int sscf_uni_start __P((void));
+int sscf_uni_stop __P((void));
+void sscf_uni_abort __P((struct univcc *, char *));
+void sscf_uni_pdu_print __P((struct univcc *, KBuffer *,
+ char *));
+
+ /* sscf_uni_lower.c */
+void sscf_uni_lower __P((int, void *, int, int));
+
+ /* sscf_uni_upper.c */
+void sscf_uni_upper __P((int, void *, int, int));
+
+
+/*
+ * External variables
+ */
+extern int sscf_uni_vccnt;
+
+#endif /* ATM_KERNEL */
+
+#endif /* _UNI_SSCF_UNI_VAR_H */
diff --git a/sys/netatm/uni/sscop.c b/sys/netatm/uni/sscop.c
new file mode 100644
index 0000000..d65118b
--- /dev/null
+++ b/sys/netatm/uni/sscop.c
@@ -0,0 +1,409 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ *
+ * @(#) $Id: sscop.c,v 1.6 1998/03/24 21:10:43 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * Service Specific Connection Oriented Protocol (SSCOP)
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: sscop.c,v 1.6 1998/03/24 21:10:43 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/uni.h>
+#include <netatm/uni/sscop.h>
+#include <netatm/uni/sscop_misc.h>
+#include <netatm/uni/sscop_pdu.h>
+#include <netatm/uni/sscop_var.h>
+
+
+/*
+ * Global variables
+ */
+int sscop_vccnt = 0;
+
+struct sscop *sscop_head = NULL;
+
+struct sscop_stat sscop_stat = {0};
+
+struct atm_time sscop_timer = {0, 0};
+
+struct sp_info sscop_pool = {
+ "sscop pool", /* si_name */
+ sizeof(struct sscop), /* si_blksiz */
+ 5, /* si_blkcnt */
+ 100 /* si_maxallow */
+};
+
+
+/*
+ * Local functions
+ */
+static int sscop_inst __P((struct stack_defn **, Atm_connvc *));
+
+
+/*
+ * Local variables
+ */
+static struct stack_defn sscop_service = {
+ NULL,
+ SAP_SSCOP,
+ 0,
+ sscop_inst,
+ sscop_lower,
+ sscop_upper,
+ 0
+};
+
+static struct t_atm_cause sscop_cause = {
+ T_ATM_ITU_CODING,
+ T_ATM_LOC_USER,
+ T_ATM_CAUSE_TEMPORARY_FAILURE,
+ {0, 0, 0, 0}
+};
+
+static u_char sscop_maa_log[MAA_ERROR_COUNT] = {
+ 1, /* A */
+ 1, /* B */
+ 1, /* C */
+ 1, /* D */
+ 1, /* E */
+ 1, /* F */
+ 1, /* G */
+ 1, /* H */
+ 1, /* I */
+ 1, /* J */
+ 1, /* K */
+ 1, /* L */
+ 1, /* M */
+ 0, /* N */
+ 0, /* O */
+ 0, /* P */
+ 1, /* Q */
+ 1, /* R */
+ 1, /* S */
+ 1, /* T */
+ 1, /* U */
+ 0, /* V */
+ 0, /* W */
+ 0, /* X */
+ 1 /* INVAL */
+};
+
+
+/*
+ * Initialize SSCOP processing
+ *
+ * This will be called during module loading. We will register our stack
+ * service and wait for someone to talk to us.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 initialization was successful
+ * errno initialization failed - reason indicated
+ *
+ */
+int
+sscop_start()
+{
+ int err = 0;
+
+ /*
+ * Register stack service
+ */
+ if (err = atm_stack_register(&sscop_service))
+ goto done;
+
+ /*
+ * Start up timer
+ */
+ atm_timeout(&sscop_timer, ATM_HZ/SSCOP_HZ, sscop_timeout);
+
+done:
+ return (err);
+}
+
+
+/*
+ * Terminate SSCOP processing
+ *
+ * This will be called just prior to unloading the module from memory. All
+ * signalling instances should have been terminated by now, so we just free
+ * up all of our resources.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 termination was successful
+ * errno termination failed - reason indicated
+ *
+ */
+int
+sscop_stop()
+{
+ int err = 0;
+
+ /*
+ * Any connections still exist??
+ */
+ if (sscop_vccnt) {
+
+ /*
+ * Yes, can't stop yet
+ */
+ return (EBUSY);
+ }
+
+ /*
+ * Stop our timer
+ */
+ (void) atm_untimeout(&sscop_timer);
+
+ /*
+ * Deregister the stack service
+ */
+ (void) atm_stack_deregister(&sscop_service);
+
+ /*
+ * Free our storage pools
+ */
+ atm_release_pool(&sscop_pool);
+
+done:
+ return (err);
+}
+
+
+/*
+ * SSCOP Stack Instantiation
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * ssp pointer to array of stack definition pointers for connection
+ * ssp[0] points to upper layer's stack service definition
+ * ssp[1] points to this layer's stack service definition
+ * ssp[2] points to lower layer's stack service definition
+ * cvp pointer to connection vcc for this stack
+ *
+ * Returns:
+ * 0 instantiation successful
+ * errno instantiation failed - reason indicated
+ *
+ */
+static int
+sscop_inst(ssp, cvp)
+ struct stack_defn **ssp;
+ Atm_connvc *cvp;
+{
+ struct stack_defn *sdp_up = ssp[0],
+ *sdp_me = ssp[1],
+ *sdp_low = ssp[2];
+ struct sscop *sop;
+ int err;
+
+ ATM_DEBUG2("sscop_inst: ssp=0x%x, cvp=0x%x\n", ssp, cvp);
+
+ /*
+ * Validate lower SAP
+ */
+ if ((sdp_low->sd_sap & SAP_CLASS_MASK) != SAP_CPCS)
+ return (EINVAL);
+
+ /*
+ * Allocate our control block
+ */
+ sop = (struct sscop *)atm_allocate(&sscop_pool);
+ if (sop == NULL)
+ return (ENOMEM);
+
+ sop->so_state = SOS_INST;
+ sop->so_connvc = cvp;
+ sop->so_toku = sdp_up->sd_toku;
+ sop->so_upper = sdp_up->sd_upper;
+
+ /*
+ * Store my token into service definition
+ */
+ sdp_me->sd_toku = sop;
+
+ /*
+ * Update and save input buffer headroom
+ */
+ HEADIN(cvp, sizeof(struct pdu_hdr), 0);
+ /* sop->so_headin = cvp->cvc_attr.headin; */
+
+ /*
+ * Pass instantiation down the stack
+ */
+ err = sdp_low->sd_inst(ssp + 1, cvp);
+ if (err) {
+ /*
+ * Lower layer instantiation failed, free our resources
+ */
+ atm_free((caddr_t)sop);
+ return (err);
+ }
+
+ /*
+ * Link in connection block
+ */
+ LINK2TAIL(sop, struct sscop, sscop_head, so_next);
+ sscop_vccnt++;
+ sscop_stat.sos_connects++;
+
+ /*
+ * Save and update output buffer headroom
+ */
+ sop->so_headout = cvp->cvc_attr.headout;
+ HEADOUT(cvp, sizeof(struct pdu_hdr), 0);
+
+ /*
+ * Save lower layer's interface info
+ */
+ sop->so_lower = sdp_low->sd_lower;
+ sop->so_tokl = sdp_low->sd_toku;
+
+ /*
+ * Initialize version (until INIT received)
+ */
+ sop->so_vers = SSCOP_VERS_Q2110;
+
+ return (0);
+}
+
+
+/*
+ * Report Management Error
+ *
+ * Called to report an error to the layer management entity.
+ *
+ * Arguments:
+ * sop pointer to sscop control block
+ * code error code
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_maa_error(sop, code)
+ struct sscop *sop;
+ int code;
+{
+ int i;
+
+ /*
+ * Validate error code
+ */
+ if ((code < MAA_ERROR_MIN) ||
+ (code > MAA_ERROR_MAX))
+ code = MAA_ERROR_INVAL;
+ i = code - MAA_ERROR_MIN;
+
+ /*
+ * Bump statistics counters
+ */
+ sscop_stat.sos_maa_error[i]++;
+
+ /*
+ * Log error message
+ */
+ if (sscop_maa_log[i] != 0) {
+ struct vccb *vcp = sop->so_connvc->cvc_vcc;
+ struct atm_pif *pip = vcp->vc_pif;
+
+ log(LOG_ERR,
+ "sscop_maa_error: intf=%s%d vpi=%d vci=%d code=%c state=%d\n",
+ pip->pif_name, pip->pif_unit,
+ vcp->vc_vpi, vcp->vc_vci, code, sop->so_state);
+ }
+}
+
+
+/*
+ * Abort an SSCOP connection
+ *
+ * Called when an unrecoverable or "should never happen" error occurs.
+ * We log a message, send an END PDU to our peer and request the signalling
+ * manager to abort the connection.
+ *
+ * Arguments:
+ * sop pointer to sscop control block
+ * msg pointer to error message
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_abort(sop, msg)
+ struct sscop *sop;
+ char *msg;
+{
+ Atm_connvc *cvp = sop->so_connvc;
+
+ /*
+ * Log and count error
+ */
+ log(LOG_ERR, msg);
+ sscop_stat.sos_aborts++;
+
+ /*
+ * Send an END PDU as a courtesy to peer
+ */
+ (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
+
+ /*
+ * Set termination state
+ */
+ sop->so_state = SOS_TERM;
+
+ /*
+ * Flush all of our queues
+ */
+ sscop_xmit_drain(sop);
+ sscop_rcvr_drain(sop);
+
+ /*
+ * Tell Connection Manager to abort this connection
+ */
+ (void) atm_cm_abort(cvp, &sscop_cause);
+}
+
diff --git a/sys/netatm/uni/sscop.h b/sys/netatm/uni/sscop.h
new file mode 100644
index 0000000..2f786b3
--- /dev/null
+++ b/sys/netatm/uni/sscop.h
@@ -0,0 +1,80 @@
+/*
+ *
+ * ===================================
+ * 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: sscop.h,v 1.4 1998/08/26 23:29:19 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * SSCOP protocol definitions
+ *
+ */
+
+#ifndef _UNI_SSCOP_H
+#define _UNI_SSCOP_H
+
+/*
+ * SSCOP Version
+ */
+enum sscop_vers {
+ SSCOP_VERS_QSAAL, /* Version = Q.SAAL1 */
+ SSCOP_VERS_Q2110 /* Version = Q.2110 */
+};
+
+
+/*
+ * SSCOP API definitions
+ */
+#define SSCOP_UU_NULL 0 /* User-to-User Info = null */
+#define SSCOP_RN_TOTAL -1 /* Retrieval Number = Total */
+#define SSCOP_RN_UNKNOWN -2 /* Retrieval Number = Unknown */
+#define SSCOP_BR_YES 1 /* Buffer Release = Yes */
+#define SSCOP_BR_NO 2 /* Buffer Release = No */
+#define SSCOP_SOURCE_SSCOP 1 /* Source = SSCOP */
+#define SSCOP_SOURCE_USER 2 /* Source = User */
+#define SSCOP_SOURCE_LAST 3 /* Source = from last END */
+
+
+/*
+ * Connection parameters for an SSCOP entity.
+ * Passed via an SSCOP_INIT stack call argument.
+ */
+struct sscop_parms {
+ u_short sp_maxinfo; /* k - max information field size */
+ u_short sp_maxuu; /* j - max SSCOP-UU field size */
+ short sp_maxcc; /* MaxCC - max value of VT(CC) */
+ short sp_maxpd; /* MaxPD - max value of VT(PD) */
+ u_short sp_timecc; /* Timer_CC value (ticks) */
+ u_short sp_timekeep; /* Timer_KEEPALIVE value (ticks) */
+ u_short sp_timeresp; /* Timer_NO-RESPONSE value (ticks) */
+ u_short sp_timepoll; /* Timer_POLL value (ticks) */
+ u_short sp_timeidle; /* Timer_IDLE value (ticks) */
+ short sp_rcvwin; /* Receiver window size */
+};
+
+#endif /* _UNI_SSCOP_H */
diff --git a/sys/netatm/uni/sscop_lower.c b/sys/netatm/uni/sscop_lower.c
new file mode 100644
index 0000000..f76f702
--- /dev/null
+++ b/sys/netatm/uni/sscop_lower.c
@@ -0,0 +1,349 @@
+/*
+ *
+ * ===================================
+ * 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: sscop_lower.c,v 1.6 1998/04/07 23:21:28 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * SSCOP - SSCOP SAP interface processing
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: sscop_lower.c,v 1.6 1998/04/07 23:21:28 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/uni.h>
+#include <netatm/uni/sscop.h>
+#include <netatm/uni/sscop_misc.h>
+#include <netatm/uni/sscop_pdu.h>
+#include <netatm/uni/sscop_var.h>
+
+
+/*
+ * Local variables
+ */
+/*
+ * Stack commands with arg1 containing an buffer pointer
+ */
+static u_char sscop_buf1[] = {
+ 0,
+ 0, /* SSCOP_INIT */
+ 0, /* SSCOP_TERM */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1, /* SSCOP_ESTABLISH_REQ */
+ 0,
+ 1, /* SSCOP_ESTABLISH_RSP */
+ 0,
+ 1, /* SSCOP_RELEASE_REQ */
+ 0,
+ 0,
+ 1, /* SSCOP_DATA_REQ */
+ 0,
+ 1, /* SSCOP_RESYNC_REQ */
+ 0,
+ 0, /* SSCOP_RESYNC_RSP */
+ 0,
+ 0,
+ 0, /* SSCOP_RECOVER_RSP */
+ 1, /* SSCOP_UNITDATA_REQ */
+ 0,
+ 0, /* SSCOP_RETRIEVE_REQ */
+ 0,
+ 0
+};
+
+
+/*
+ * SSCOP Lower Stack Command Handler
+ *
+ * This function will receive all of the stack commands issued from the
+ * layer above SSCOP (ie. using the SSCOP SAP). The appropriate processing
+ * function will be determined based on the received stack command and the
+ * current sscop control block state.
+ *
+ * Arguments:
+ * cmd stack command code
+ * tok session token
+ * arg1 command specific argument
+ * arg2 command specific argument
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_lower(cmd, tok, arg1, arg2)
+ int cmd;
+ void *tok;
+ int arg1;
+ int arg2;
+{
+ struct sscop *sop = (struct sscop *)tok;
+ void (**stab) __P((struct sscop *, int, int));
+ void (*func) __P((struct sscop *, int, int));
+ int val;
+
+ ATM_DEBUG5("sscop_lower: cmd=0x%x, sop=0x%x, state=%d, arg1=0x%x, arg2=0x%x\n",
+ cmd, (int)sop, sop->so_state, arg1, arg2);
+
+ /*
+ * Validate stack command
+ */
+ val = cmd & STKCMD_VAL_MASK;
+ if (((u_int)cmd < (u_int)SSCOP_CMD_MIN) ||
+ ((u_int)cmd > (u_int)SSCOP_CMD_MAX) ||
+ ((stab = (sop->so_vers == SSCOP_VERS_QSAAL ?
+ sscop_qsaal_aatab[val] :
+ sscop_q2110_aatab[val])) == NULL)) {
+ log(LOG_ERR, "sscop_lower: unknown cmd 0x%x, sop=0x%x\n",
+ cmd, (int)sop);
+ return;
+ }
+
+ /*
+ * Validate sscop state
+ */
+ if (sop->so_state > SOS_MAXSTATE) {
+ log(LOG_ERR, "sscop_lower: invalid state sop=0x%x, state=%d\n",
+ (int)sop, sop->so_state);
+ /*
+ * Release possible buffer
+ */
+ if (sscop_buf1[val]) {
+ if (arg1)
+ KB_FREEALL((KBuffer *)arg1);
+ }
+ return;
+ }
+
+ /*
+ * Validate command/state combination
+ */
+ func = stab[sop->so_state];
+ if (func == NULL) {
+ log(LOG_ERR,
+ "sscop_lower: invalid cmd/state: sop=0x%x, cmd=0x%x, state=%d\n",
+ (int)sop, cmd, sop->so_state);
+ /*
+ * Release possible buffer
+ */
+ if (sscop_buf1[val]) {
+ if (arg1)
+ KB_FREEALL((KBuffer *)arg1);
+ }
+ return;
+ }
+
+ /*
+ * Call event processing function
+ */
+ (*func)(sop, arg1, arg2);
+
+ return;
+}
+
+
+/*
+ * No-op Processor (no buffers)
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * arg1 command-specific argument
+ * arg2 command-specific argument
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_aa_noop_0(sop, arg1, arg2)
+ struct sscop *sop;
+ int arg1;
+ int arg2;
+{
+ /*
+ * Nothing to do
+ */
+ return;
+}
+
+
+/*
+ * No-op Processor (arg1 == buffer)
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * arg1 command-specific argument (buffer pointer)
+ * arg2 command-specific argument
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_aa_noop_1(sop, arg1, arg2)
+ struct sscop *sop;
+ int arg1;
+ int arg2;
+{
+
+ /*
+ * Just free buffer chain
+ */
+ if (arg1)
+ KB_FREEALL((KBuffer *)arg1);
+
+ return;
+}
+
+
+/*
+ * SSCOP_INIT / SOS_INST Command Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * arg1 command specific argument
+ * arg2 command specific argument
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_init_inst(sop, arg1, arg2)
+ struct sscop *sop;
+ int arg1;
+ int arg2;
+{
+ int err;
+
+ /*
+ * Make ourselves ready and pass on the INIT
+ */
+ sop->so_state = SOS_IDLE;
+
+ /*
+ * Validate SSCOP version to use
+ */
+ switch ((enum sscop_vers)arg1) {
+ case SSCOP_VERS_QSAAL:
+ break;
+
+ case SSCOP_VERS_Q2110:
+ break;
+
+ default:
+ sscop_abort(sop, "sscop: bad version\n");
+ return;
+ }
+ sop->so_vers = (enum sscop_vers)arg1;
+
+ /*
+ * Copy SSCOP connection parameters to use
+ */
+ sop->so_parm = *(struct sscop_parms *)arg2;
+
+ /*
+ * Initialize lower layers
+ */
+ STACK_CALL(CPCS_INIT, sop->so_lower, sop->so_tokl, sop->so_connvc,
+ 0, 0, err);
+ if (err) {
+ /*
+ * Should never happen
+ */
+ sscop_abort(sop, "sscop: INIT failure\n");
+ return;
+ }
+ return;
+}
+
+
+/*
+ * SSCOP_TERM / SOS_* Command Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * arg1 command specific argument
+ * arg2 command specific argument
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_term_all(sop, arg1, arg2)
+ struct sscop *sop;
+ int arg1;
+ int arg2;
+{
+ int err;
+
+ /*
+ * Set termination state
+ */
+ sop->so_state = SOS_TERM;
+
+ /*
+ * Pass the TERM down the stack
+ */
+ STACK_CALL(CPCS_TERM, sop->so_lower, sop->so_tokl, sop->so_connvc,
+ 0, 0, err);
+ if (err) {
+ /*
+ * Should never happen
+ */
+ sscop_abort(sop, "sscop: TERM failure\n");
+ return;
+ }
+
+ /*
+ * Unlink and free the connection block
+ */
+ UNLINK(sop, struct sscop, sscop_head, so_next);
+ atm_free((caddr_t)sop);
+ sscop_vccnt--;
+ return;
+}
+
diff --git a/sys/netatm/uni/sscop_misc.h b/sys/netatm/uni/sscop_misc.h
new file mode 100644
index 0000000..4348cef
--- /dev/null
+++ b/sys/netatm/uni/sscop_misc.h
@@ -0,0 +1,97 @@
+/*
+ *
+ * ===================================
+ * 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: sscop_misc.h,v 1.4 1998/08/26 23:29:19 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * SSCOP miscellaneous definitions
+ *
+ */
+
+#ifndef _UNI_SSCOP_MISC_H
+#define _UNI_SSCOP_MISC_H
+
+/*
+ * SSCOP command definitions
+ */
+#define SSCOP_CMD_MIN SSCOP_INIT /* Minimum SSCOP CMD value */
+#define SSCOP_CMD_MAX SSCOP_RETRIEVECMP_IND /* Maximum SSCOP CMD value */
+#define SSCOP_CMD_SIZE 36 /* Size of command lookup table */
+
+
+/*
+ * Management Errors
+ */
+#define MAA_ERROR_MIN 'A'
+#define MAA_ERROR_MAX 'X'
+#define MAA_ERROR_INVAL (MAA_ERROR_MAX + 1)
+#define MAA_ERROR_COUNT (MAA_ERROR_MAX - MAA_ERROR_MIN + 2)
+
+
+/*
+ * SSCOP Sequence Numbers
+ *
+ * SSCOP sequence numbers are 24 bit integers using modulo arithmetic.
+ * The macros below must be used to modify and compare such numbers.
+ * Comparison of sequence numbers is always relative to some base number (b).
+ */
+typedef u_int sscop_seq;
+
+#define SEQ_MOD 0xffffff
+#define SEQ_VAL(v) ((v) & SEQ_MOD)
+#define SEQ_SET(s,v) ((s) = SEQ_VAL(v))
+#define SEQ_ADD(s,v) (SEQ_VAL((s) + (v)))
+#define SEQ_SUB(s,v) (SEQ_VAL((s) - (v)))
+#define SEQ_INCR(s,v) ((s) = SEQ_VAL((s) + (v)))
+#define SEQ_DECR(s,v) ((s) = SEQ_VAL((s) - (v)))
+#define SEQ_EQ(x,y) (SEQ_VAL(x) == SEQ_VAL(y))
+#define SEQ_NEQ(x,y) (SEQ_VAL(x) != SEQ_VAL(y))
+#define SEQ_LT(x,y,b) (SEQ_VAL((x) - (b)) < SEQ_VAL((y) - (b)))
+#define SEQ_LEQ(x,y,b) (SEQ_VAL((x) - (b)) <= SEQ_VAL((y) - (b)))
+#define SEQ_GT(x,y,b) (SEQ_VAL((x) - (b)) > SEQ_VAL((y) - (b)))
+#define SEQ_GEQ(x,y,b) (SEQ_VAL((x) - (b)) >= SEQ_VAL((y) - (b)))
+
+
+/*
+ * SSCOP Timers
+ *
+ * All of the SSCOP timer fields are maintained in terms of clock ticks.
+ * The timers tick 2 times per second.
+ */
+#define SSCOP_HZ 2 /* SSCOP ticks per second */
+
+#define SSCOP_T_NUM 4 /* Number of timers per connection */
+
+#define SSCOP_T_POLL 0 /* Timer_POLL / Timer_KEEP-ALIVE */
+#define SSCOP_T_NORESP 1 /* Timer_NO-RESPONSE */
+#define SSCOP_T_CC 2 /* Timer_CC */
+#define SSCOP_T_IDLE 3 /* Timer_IDLE */
+
+#endif /* _UNI_SSCOP_MISC_H */
diff --git a/sys/netatm/uni/sscop_pdu.c b/sys/netatm/uni/sscop_pdu.c
new file mode 100644
index 0000000..b9aec03
--- /dev/null
+++ b/sys/netatm/uni/sscop_pdu.c
@@ -0,0 +1,1237 @@
+/*
+ *
+ * ===================================
+ * 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: sscop_pdu.c,v 1.6 1998/04/07 23:21:36 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * SSCOP - PDU subroutines
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: sscop_pdu.c,v 1.6 1998/04/07 23:21:36 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/uni.h>
+#include <netatm/uni/sscop.h>
+#include <netatm/uni/sscop_misc.h>
+#include <netatm/uni/sscop_pdu.h>
+#include <netatm/uni/sscop_var.h>
+
+/*
+ * Local functions
+ */
+static KBuffer * sscop_stat_init __P((struct sscop *));
+static KBuffer * sscop_stat_add __P((sscop_seq, KBuffer *));
+static int sscop_stat_end __P((struct sscop *, sscop_seq,
+ KBuffer *, KBuffer *));
+static int sscop_recv_locate __P((struct sscop *, sscop_seq,
+ struct pdu_hdr **));
+
+
+/*
+ * Build and send BGN PDU
+ *
+ * A BGN PDU will be constructed and passed down the protocol stack.
+ * The SSCOP-UU/N(UU) field is not supported.
+ *
+ * Arguments:
+ * sop pointer to sscop connection control block
+ * source originator of BGN PDU (Q.SAAL1 only)
+ *
+ * Returns:
+ * 0 PDU successfully built and passed down the stack
+ * else unable to build or send pdu
+ *
+ */
+int
+sscop_send_bgn(sop, source)
+ struct sscop *sop;
+ int source;
+{
+ KBuffer *m;
+ struct bgn_pdu *bp;
+ int err;
+
+
+ /*
+ * Get buffer for PDU
+ */
+ KB_ALLOCPKT(m, sizeof(struct bgn_pdu), KB_F_NOWAIT, KB_T_HEADER);
+ if (m == NULL)
+ return (1);
+
+ /*
+ * Setup buffer controls
+ */
+ KB_HEADSET(m, MIN(sop->so_headout,
+ KB_BFRLEN(m) - sizeof(struct bgn_pdu)));
+ KB_LEN(m) = sizeof(struct bgn_pdu);
+
+ /*
+ * Build PDU
+ */
+ KB_DATASTART(m, bp, struct bgn_pdu *);
+ *(int *)&bp->bgn_rsvd[0] = 0;
+ if (sop->so_vers != SSCOP_VERS_QSAAL)
+ bp->bgn_nsq = sop->so_sendconn;
+ bp->bgn_nmr =
+ htonl((PT_BGN << PT_TYPE_SHIFT) | SEQ_VAL(sop->so_rcvmax));
+ if ((sop->so_vers == SSCOP_VERS_QSAAL) &&
+ (source == SSCOP_SOURCE_SSCOP))
+ bp->bgn_type |= PT_SOURCE_SSCOP;
+
+ /*
+ * Send PDU towards peer
+ */
+ STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
+ sop->so_connvc, (int)m, 0, err);
+
+ if (err)
+ KB_FREEALL(m);
+
+ return (err);
+}
+
+
+/*
+ * Build and send BGAK PDU
+ *
+ * A BGAK PDU will be constructed and passed down the protocol stack.
+ * The SSCOP-UU/N(UU) field is not supported.
+ *
+ * Arguments:
+ * sop pointer to sscop connection control block
+ *
+ * Returns:
+ * 0 PDU successfully built and passed down the stack
+ * else unable to build or send pdu
+ *
+ */
+int
+sscop_send_bgak(sop)
+ struct sscop *sop;
+{
+ KBuffer *m;
+ struct bgak_pdu *bp;
+ int err;
+
+
+ /*
+ * Get buffer for PDU
+ */
+ KB_ALLOCPKT(m, sizeof(struct bgak_pdu), KB_F_NOWAIT, KB_T_HEADER);
+ if (m == NULL)
+ return (1);
+
+ /*
+ * Setup buffer controls
+ */
+ KB_HEADSET(m, MIN(sop->so_headout,
+ KB_BFRLEN(m) - sizeof(struct bgak_pdu)));
+ KB_LEN(m) = sizeof(struct bgak_pdu);
+
+ /*
+ * Build PDU
+ */
+ KB_DATASTART(m, bp, struct bgak_pdu *);
+ bp->bgak_rsvd = 0;
+ bp->bgak_nmr =
+ htonl((PT_BGAK << PT_TYPE_SHIFT) | SEQ_VAL(sop->so_rcvmax));
+
+ /*
+ * Send PDU towards peer
+ */
+ STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
+ sop->so_connvc, (int)m, 0, err);
+
+ if (err)
+ KB_FREEALL(m);
+
+ return (err);
+}
+
+
+/*
+ * Build and send BGREJ PDU
+ *
+ * A BGREJ PDU will be constructed and passed down the protocol stack.
+ * The SSCOP-UU/N(UU) field is not supported.
+ *
+ * Arguments:
+ * sop pointer to sscop connection control block
+ *
+ * Returns:
+ * 0 PDU successfully built and passed down the stack
+ * else unable to build or send pdu
+ *
+ */
+int
+sscop_send_bgrej(sop)
+ struct sscop *sop;
+{
+ KBuffer *m;
+ struct bgrej_pdu *bp;
+ int err;
+
+
+ /*
+ * Get buffer for PDU
+ */
+ KB_ALLOCPKT(m, sizeof(struct bgrej_pdu), KB_F_NOWAIT, KB_T_HEADER);
+ if (m == NULL)
+ return (1);
+
+ /*
+ * Setup buffer controls
+ */
+ KB_HEADSET(m, MIN(sop->so_headout,
+ KB_BFRLEN(m) - sizeof(struct bgrej_pdu)));
+ KB_LEN(m) = sizeof(struct bgrej_pdu);
+
+ /*
+ * Build PDU
+ */
+ KB_DATASTART(m, bp, struct bgrej_pdu *);
+ bp->bgrej_rsvd2 = 0;
+ *(u_int *)&bp->bgrej_type = htonl((PT_BGREJ << PT_TYPE_SHIFT) | 0);
+
+ /*
+ * Send PDU towards peer
+ */
+ STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
+ sop->so_connvc, (int)m, 0, err);
+
+ if (err)
+ KB_FREEALL(m);
+
+ return (err);
+}
+
+
+/*
+ * Build and send END PDU
+ *
+ * An END PDU will be constructed and passed down the protocol stack.
+ * The SSCOP-UU/N(UU) field is not supported.
+ *
+ * Arguments:
+ * sop pointer to sscop connection control block
+ * source originator of END PDU
+ *
+ * Returns:
+ * 0 PDU successfully built and passed down the stack
+ * else unable to build or send pdu
+ *
+ */
+int
+sscop_send_end(sop, source)
+ struct sscop *sop;
+ int source;
+{
+ KBuffer *m;
+ struct end_pdu *ep;
+ int err;
+
+
+ /*
+ * Get buffer for PDU
+ */
+ KB_ALLOCPKT(m, sizeof(struct end_pdu), KB_F_NOWAIT, KB_T_HEADER);
+ if (m == NULL)
+ return (1);
+
+ /*
+ * Setup buffer controls
+ */
+ KB_HEADSET(m, MIN(sop->so_headout,
+ KB_BFRLEN(m) - sizeof(struct end_pdu)));
+ KB_LEN(m) = sizeof(struct end_pdu);
+
+ /*
+ * Build PDU
+ */
+ KB_DATASTART(m, ep, struct end_pdu *);
+ ep->end_rsvd2 = 0;
+ *(u_int *)&ep->end_type = htonl((PT_END << PT_TYPE_SHIFT) | 0);
+ if (source == SSCOP_SOURCE_SSCOP) {
+ ep->end_type |= PT_SOURCE_SSCOP;
+ sop->so_flags |= SOF_ENDSSCOP;
+ } else if (source == SSCOP_SOURCE_USER)
+ sop->so_flags &= ~SOF_ENDSSCOP;
+ else if ((source == SSCOP_SOURCE_LAST) &&
+ (sop->so_flags & SOF_ENDSSCOP))
+ ep->end_type |= PT_SOURCE_SSCOP;
+
+ /*
+ * Send PDU towards peer
+ */
+ STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
+ sop->so_connvc, (int)m, 0, err);
+
+ if (err)
+ KB_FREEALL(m);
+
+ return (err);
+}
+
+
+/*
+ * Build and send ENDAK PDU
+ *
+ * An ENDAK PDU will be constructed and passed down the protocol stack.
+ *
+ * Arguments:
+ * sop pointer to sscop connection control block
+ *
+ * Returns:
+ * 0 PDU successfully built and passed down the stack
+ * else unable to build or send pdu
+ *
+ */
+int
+sscop_send_endak(sop)
+ struct sscop *sop;
+{
+ KBuffer *m;
+ struct endak_q2110_pdu *e2p;
+ struct endak_qsaal_pdu *esp;
+ int err, size;
+
+
+ /*
+ * Get size of PDU
+ */
+ if (sop->so_vers == SSCOP_VERS_QSAAL)
+ size = sizeof(struct endak_qsaal_pdu);
+ else
+ size = sizeof(struct endak_q2110_pdu);
+
+ /*
+ * Get buffer for PDU
+ */
+ KB_ALLOCPKT(m, size, KB_F_NOWAIT, KB_T_HEADER);
+ if (m == NULL)
+ return (1);
+
+ /*
+ * Setup buffer controls
+ */
+ KB_HEADSET(m, MIN(sop->so_headout, KB_BFRLEN(m) - size));
+ KB_LEN(m) = size;
+
+ /*
+ * Build PDU
+ */
+ if (sop->so_vers == SSCOP_VERS_QSAAL) {
+ KB_DATASTART(m, esp, struct endak_qsaal_pdu *);
+ *(u_int *)&esp->endak_type =
+ htonl((PT_ENDAK << PT_TYPE_SHIFT) | 0);
+ } else {
+ KB_DATASTART(m, e2p, struct endak_q2110_pdu *);
+ e2p->endak_rsvd2 = 0;
+ *(u_int *)&e2p->endak_type =
+ htonl((PT_ENDAK << PT_TYPE_SHIFT) | 0);
+ }
+
+ /*
+ * Send PDU towards peer
+ */
+ STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
+ sop->so_connvc, (int)m, 0, err);
+
+ if (err)
+ KB_FREEALL(m);
+
+ return (err);
+}
+
+
+/*
+ * Build and send RS PDU
+ *
+ * A RS PDU will be constructed and passed down the protocol stack.
+ * The SSCOP-UU/N(UU) field is not supported.
+ *
+ * Arguments:
+ * sop pointer to sscop connection control block
+ *
+ * Returns:
+ * 0 PDU successfully built and passed down the stack
+ * else unable to build or send pdu
+ *
+ */
+int
+sscop_send_rs(sop)
+ struct sscop *sop;
+{
+ KBuffer *m;
+ struct rs_pdu *rp;
+ int err;
+
+
+ /*
+ * Get buffer for PDU
+ */
+ KB_ALLOCPKT(m, sizeof(struct rs_pdu), KB_F_NOWAIT, KB_T_HEADER);
+ if (m == NULL)
+ return (1);
+
+ /*
+ * Setup buffer controls
+ */
+ KB_HEADSET(m, MIN(sop->so_headout,
+ KB_BFRLEN(m) - sizeof(struct rs_pdu)));
+ KB_LEN(m) = sizeof(struct rs_pdu);
+
+ /*
+ * Build PDU
+ */
+ KB_DATASTART(m, rp, struct rs_pdu *);
+ *(int *)&rp->rs_rsvd[0] = 0;
+ if (sop->so_vers != SSCOP_VERS_QSAAL) {
+ rp->rs_nsq = sop->so_sendconn;
+ rp->rs_nmr = htonl((PT_RS << PT_TYPE_SHIFT) |
+ SEQ_VAL(sop->so_rcvmax));
+ } else {
+ rp->rs_nmr = htonl((PT_RS << PT_TYPE_SHIFT) | 0);
+ }
+
+ /*
+ * Send PDU towards peer
+ */
+ STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
+ sop->so_connvc, (int)m, 0, err);
+
+ if (err)
+ KB_FREEALL(m);
+
+ return (err);
+}
+
+
+/*
+ * Build and send RSAK PDU
+ *
+ * An RSAK PDU will be constructed and passed down the protocol stack.
+ *
+ * Arguments:
+ * sop pointer to sscop connection control block
+ *
+ * Returns:
+ * 0 PDU successfully built and passed down the stack
+ * else unable to build or send pdu
+ *
+ */
+int
+sscop_send_rsak(sop)
+ struct sscop *sop;
+{
+ KBuffer *m;
+ struct rsak_q2110_pdu *r2p;
+ struct rsak_qsaal_pdu *rsp;
+ int err, size;
+
+
+ /*
+ * Get size of PDU
+ */
+ if (sop->so_vers == SSCOP_VERS_QSAAL)
+ size = sizeof(struct rsak_qsaal_pdu);
+ else
+ size = sizeof(struct rsak_q2110_pdu);
+
+ /*
+ * Get buffer for PDU
+ */
+ KB_ALLOCPKT(m, size, KB_F_NOWAIT, KB_T_HEADER);
+ if (m == NULL)
+ return (1);
+
+ /*
+ * Setup buffer controls
+ */
+ KB_HEADSET(m, MIN(sop->so_headout, KB_BFRLEN(m) - size));
+ KB_LEN(m) = size;
+
+ /*
+ * Build PDU
+ */
+ if (sop->so_vers == SSCOP_VERS_QSAAL) {
+ KB_DATASTART(m, rsp, struct rsak_qsaal_pdu *);
+ *(u_int *)&rsp->rsaks_type =
+ htonl((PT_RSAK << PT_TYPE_SHIFT) | 0);
+ } else {
+ KB_DATASTART(m, r2p, struct rsak_q2110_pdu *);
+ r2p->rsak_rsvd = 0;
+ r2p->rsak_nmr = htonl((PT_RSAK << PT_TYPE_SHIFT) |
+ SEQ_VAL(sop->so_rcvmax));
+ }
+
+ /*
+ * Send PDU towards peer
+ */
+ STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
+ sop->so_connvc, (int)m, 0, err);
+
+ if (err)
+ KB_FREEALL(m);
+
+ return (err);
+}
+
+
+/*
+ * Build and send ER PDU
+ *
+ * An ER PDU will be constructed and passed down the protocol stack.
+ *
+ * Arguments:
+ * sop pointer to sscop connection control block
+ *
+ * Returns:
+ * 0 PDU successfully built and passed down the stack
+ * else unable to build or send pdu
+ *
+ */
+int
+sscop_send_er(sop)
+ struct sscop *sop;
+{
+ KBuffer *m;
+ struct er_pdu *ep;
+ int err;
+
+
+ /*
+ * Get buffer for PDU
+ */
+ KB_ALLOCPKT(m, sizeof(struct er_pdu), KB_F_NOWAIT, KB_T_HEADER);
+ if (m == NULL)
+ return (1);
+
+ /*
+ * Setup buffer controls
+ */
+ KB_HEADSET(m, MIN(sop->so_headout,
+ KB_BFRLEN(m) - sizeof(struct er_pdu)));
+ KB_LEN(m) = sizeof(struct er_pdu);
+
+ /*
+ * Build PDU
+ */
+ KB_DATASTART(m, ep, struct er_pdu *);
+ *(int *)&ep->er_rsvd[0] = 0;
+ ep->er_nsq = sop->so_sendconn;
+ ep->er_nmr = htonl((PT_ER << PT_TYPE_SHIFT) | SEQ_VAL(sop->so_rcvmax));
+
+ /*
+ * Send PDU towards peer
+ */
+ STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
+ sop->so_connvc, (int)m, 0, err);
+
+ if (err)
+ KB_FREEALL(m);
+
+ return (err);
+}
+
+
+/*
+ * Build and send ERAK PDU
+ *
+ * An ERAK PDU will be constructed and passed down the protocol stack.
+ *
+ * Arguments:
+ * sop pointer to sscop connection control block
+ *
+ * Returns:
+ * 0 PDU successfully built and passed down the stack
+ * else unable to build or send pdu
+ *
+ */
+int
+sscop_send_erak(sop)
+ struct sscop *sop;
+{
+ KBuffer *m;
+ struct erak_pdu *ep;
+ int err;
+
+
+ /*
+ * Get buffer for PDU
+ */
+ KB_ALLOCPKT(m, sizeof(struct erak_pdu), KB_F_NOWAIT, KB_T_HEADER);
+ if (m == NULL)
+ return (1);
+
+ /*
+ * Setup buffer controls
+ */
+ KB_HEADSET(m, MIN(sop->so_headout,
+ KB_BFRLEN(m) - sizeof(struct erak_pdu)));
+ KB_LEN(m) = sizeof(struct erak_pdu);
+
+ /*
+ * Build PDU
+ */
+ KB_DATASTART(m, ep, struct erak_pdu *);
+ ep->erak_rsvd = 0;
+ ep->erak_nmr = htonl((PT_ERAK << PT_TYPE_SHIFT) |
+ SEQ_VAL(sop->so_rcvmax));
+
+ /*
+ * Send PDU towards peer
+ */
+ STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
+ sop->so_connvc, (int)m, 0, err);
+
+ if (err)
+ KB_FREEALL(m);
+
+ return (err);
+}
+
+
+/*
+ * Build and send POLL PDU
+ *
+ * A POLL PDU will be constructed and passed down the protocol stack.
+ *
+ * Arguments:
+ * sop pointer to sscop connection control block
+ *
+ * Returns:
+ * 0 PDU successfully built and passed down the stack
+ * else unable to build or send pdu
+ *
+ */
+int
+sscop_send_poll(sop)
+ struct sscop *sop;
+{
+ KBuffer *m;
+ struct poll_pdu *pp;
+ int err;
+
+
+ /*
+ * Get buffer for PDU
+ */
+ KB_ALLOCPKT(m, sizeof(struct poll_pdu), KB_F_NOWAIT, KB_T_HEADER);
+ if (m == NULL)
+ return (1);
+
+ /*
+ * Setup buffer controls
+ */
+ KB_HEADSET(m, MIN(sop->so_headout,
+ KB_BFRLEN(m) - sizeof(struct poll_pdu)));
+ KB_LEN(m) = sizeof(struct poll_pdu);
+
+ /*
+ * Build PDU
+ */
+ KB_DATASTART(m, pp, struct poll_pdu *);
+ pp->poll_nps = htonl(SEQ_VAL(sop->so_pollsend));
+ pp->poll_ns = htonl((PT_POLL << PT_TYPE_SHIFT) | SEQ_VAL(sop->so_send));
+
+ /*
+ * Send PDU towards peer
+ */
+ STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
+ sop->so_connvc, (int)m, 0, err);
+
+ if (err)
+ KB_FREEALL(m);
+
+ return (err);
+}
+
+
+/*
+ * STAT PDU Construction - Initialize for new PDU
+ *
+ * Arguments:
+ * sop pointer to sscop connection control block
+ *
+ * Returns:
+ * addr pointer to initialized buffer
+ * 0 unable to allocate buffer
+ *
+ */
+static KBuffer *
+sscop_stat_init(sop)
+ struct sscop *sop;
+{
+ KBuffer *m;
+
+#define STAT_INIT_SIZE (sizeof(struct stat_pdu) + 2 * sizeof(sscop_seq))
+
+ /*
+ * Get buffer for PDU
+ */
+ KB_ALLOCPKT(m, STAT_INIT_SIZE, KB_F_NOWAIT, KB_T_HEADER);
+ if (m == NULL)
+ return (0);
+
+ /*
+ * Setup buffer controls
+ */
+ KB_HEADSET(m, sop->so_headout < (KB_BFRLEN(m) - STAT_INIT_SIZE) ?
+ sop->so_headout : 0);
+ KB_LEN(m) = 0;
+
+ return (m);
+#undef STAT_INIT_SIZE
+}
+
+
+/*
+ * STAT PDU Construction - Add List Element
+ *
+ * Arguments:
+ * elem sequence number to add to list
+ * m pointer to current buffer
+ *
+ * Returns:
+ * addr pointer to current buffer (updated)
+ * 0 buffer allocation failure
+ *
+ */
+static KBuffer *
+sscop_stat_add(elem, m)
+ sscop_seq elem;
+ KBuffer *m;
+{
+ KBuffer *n;
+ sscop_seq *sp;
+ int space;
+
+ /*
+ * See if new element will fit in current buffer
+ */
+ KB_TAILROOM(m, space);
+ if (space < sizeof(elem)) {
+
+ /*
+ * Nope, so get another buffer
+ */
+ KB_ALLOC(n, sizeof(elem), KB_F_NOWAIT, KB_T_DATA);
+ if (n == NULL)
+ return (0);
+
+ /*
+ * Link in new buffer
+ */
+ KB_LINK(n, m);
+ KB_LEN(n) = 0;
+ m = n;
+ }
+
+ /*
+ * Add new element
+ */
+ KB_DATAEND(m, sp, sscop_seq *);
+ *sp = htonl(elem);
+ KB_LEN(m) += sizeof (elem);
+ return (m);
+}
+
+
+/*
+ * STAT PDU Construction - Add Trailer and Send
+ *
+ * Arguments:
+ * sop pointer to sscop connection control block
+ * nps received poll sequence number (POLL.N(PS))
+ * head pointer to head of buffer chain
+ * m pointer to current (last) buffer
+ *
+ * Returns:
+ * 0 STAT successfully sent
+ * else unable to send STAT or truncated STAT was sent - buffer freed
+ *
+ */
+static int
+sscop_stat_end(sop, nps, head, m)
+ struct sscop *sop;
+ sscop_seq nps;
+ KBuffer *head;
+ KBuffer *m;
+{
+ struct stat_pdu *sp;
+ KBuffer *n;
+ int err, space, trunc = 0;
+
+ /*
+ * See if PDU trailer will fit in current buffer
+ */
+ KB_TAILROOM(m, space);
+ if (space < sizeof(struct stat_pdu)) {
+
+ /*
+ * Doesn't fit, so get another buffer
+ */
+ KB_ALLOC(n, sizeof(struct stat_pdu), KB_F_NOWAIT, KB_T_DATA);
+ if (n == NULL) {
+ /*
+ * Out of buffers - truncate elements and send
+ * what we can, but tell caller that we can't
+ * send any more segments.
+ */
+ trunc = 1;
+ do {
+ KB_LEN(m) -= sizeof(sscop_seq);
+ space += sizeof(sscop_seq);
+ } while (space < sizeof(struct stat_pdu));
+ } else {
+ /*
+ * Link in new buffer
+ */
+ KB_LINK(n, m);
+ KB_LEN(n) = 0;
+ m = n;
+ }
+ }
+
+ /*
+ * Build PDU trailer
+ */
+ KB_DATAEND(m, sp, struct stat_pdu *);
+ sp->stat_nps = htonl(nps);
+ sp->stat_nmr = htonl(sop->so_rcvmax);
+ sp->stat_nr = htonl(sop->so_rcvnext);
+ sp->stat_type = PT_STAT;
+ KB_LEN(m) += sizeof(struct stat_pdu);
+
+ /*
+ * Finally, send the STAT
+ */
+ STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
+ sop->so_connvc, (int)head, 0, err);
+
+ if (err) {
+ /*
+ * We lie about the STACK_CALL failing...
+ */
+ KB_FREEALL(head);
+ }
+
+ if (trunc)
+ return (1);
+ else
+ return (0);
+}
+
+
+/*
+ * Check for PDU in Receive Queue
+ *
+ * A receive queue will be searched for an SD PDU matching the requested
+ * sequence number. The caller must supply a pointer to the address of the
+ * PDU in the particular receive queue at which to begin the search. This
+ * function will update that pointer as it traverses the queue.
+ *
+ * Arguments:
+ * sop pointer to sscop connection control block
+ * seq sequence number of PDU to locate
+ * currp address of pointer to PDU in receive queue to start search
+ *
+ * Returns:
+ * 0 reqeusted PDU not in receive queue
+ * 1 requested PDU located in receive queue
+ *
+ */
+static int
+sscop_recv_locate(sop, seq, currp)
+ struct sscop *sop;
+ sscop_seq seq;
+ struct pdu_hdr **currp;
+{
+ sscop_seq cs;
+
+ /*
+ * Search queue until we know the answer
+ */
+ while (1) {
+ /*
+ * If we're at the end of the queue, the PDU isn't there
+ */
+ if (*currp == NULL)
+ return (0);
+
+ /*
+ * Get the current PDU sequence number
+ */
+ cs = (*currp)->ph_ns;
+
+ /*
+ * See if we're at the requested PDU
+ */
+ if (seq == cs)
+ return (1);
+
+ /*
+ * If we're past the requested seq number,
+ * the PDU isn't there
+ */
+ if (SEQ_LT(seq, cs, sop->so_rcvnext))
+ return (0);
+
+ /*
+ * Go to next PDU and keep looking
+ */
+ *currp = (*currp)->ph_recv_lk;
+ }
+}
+
+
+/*
+ * Build and send STAT PDU
+ *
+ * A STAT PDU will be constructed and passed down the protocol stack.
+ *
+ * Arguments:
+ * sop pointer to sscop connection control block
+ * nps received poll sequence number (POLL.N(PS))
+ *
+ * Returns:
+ * 0 PDU successfully built and passed down the stack
+ * else unable to build or send complete pdu
+ *
+ */
+int
+sscop_send_stat(sop, nps)
+ struct sscop *sop;
+ sscop_seq nps;
+{
+ KBuffer *head, *curr, *n;
+ struct pdu_hdr *rq = sop->so_recv_hd;
+ sscop_seq i;
+ sscop_seq vrh = sop->so_rcvhigh;
+ sscop_seq vrr = sop->so_rcvnext;
+ int len = 0;
+
+ /*
+ * Initialize for start of STAT PDU
+ */
+ head = sscop_stat_init(sop);
+ if (head == NULL)
+ return (1);
+ curr = head;
+
+ /*
+ * Start with first PDU not yet received
+ */
+ i = vrr;
+
+ /*
+ * Keep looping until we get to last sent PDU
+ */
+ while (i != vrh) {
+
+ /*
+ * Find next missing PDU
+ */
+ while (SEQ_LT(i, vrh, vrr) && sscop_recv_locate(sop, i, &rq)) {
+ SEQ_INCR(i, 1);
+ }
+
+ /*
+ * Add odd (start of missing gap) STAT element
+ */
+ n = sscop_stat_add(i, curr);
+ if (n == NULL) {
+ goto nobufs;
+ }
+ curr = n;
+ len++;
+
+ /*
+ * Have we reached the last sent PDU sequence number??
+ */
+ if (i == vrh) {
+ /*
+ * Yes, then we're done, send STAT
+ */
+ break;
+ }
+
+ /*
+ * Have we reached the max STAT size yet??
+ */
+ if (len >= PDU_MAX_ELEM) {
+ /*
+ * Yes, send this STAT segment
+ */
+ if (sscop_stat_end(sop, nps, head, curr)) {
+ return (1);
+ }
+
+ /*
+ * Start a new segment
+ */
+ head = sscop_stat_init(sop);
+ if (head == NULL)
+ return (1);
+ curr = head;
+
+ /*
+ * Restart missing gap
+ */
+ curr = sscop_stat_add(i, curr);
+ if (curr == NULL) {
+ KB_FREEALL(head);
+ return (1);
+ }
+ len = 1;
+ }
+
+ /*
+ * Now find the end of the missing gap
+ */
+ do {
+ SEQ_INCR(i, 1);
+ } while (SEQ_LT(i, vrh, vrr) &&
+ (sscop_recv_locate(sop, i, &rq) == 0));
+
+ /*
+ * Add even (start of received gap) STAT element
+ */
+ n = sscop_stat_add(i, curr);
+ if (n == NULL) {
+ goto nobufs;
+ }
+ curr = n;
+ len++;
+ }
+
+ /*
+ * Finally, send the STAT PDU (or last STAT segment)
+ */
+ if (sscop_stat_end(sop, nps, head, curr)) {
+ return (1);
+ }
+
+ return (0);
+
+nobufs:
+ /*
+ * Send a truncated STAT PDU
+ */
+ sscop_stat_end(sop, nps, head, curr);
+
+ return (1);
+}
+
+
+/*
+ * Build and send USTAT PDU
+ *
+ * A USTAT PDU will be constructed and passed down the protocol stack.
+ *
+ * Arguments:
+ * sop pointer to sscop connection control block
+ * ns sequence number for second list element
+ *
+ * Returns:
+ * 0 PDU successfully built and passed down the stack
+ * else unable to build or send pdu
+ *
+ */
+int
+sscop_send_ustat(sop, ns)
+ struct sscop *sop;
+ sscop_seq ns;
+{
+ KBuffer *m;
+ struct ustat_pdu *up;
+ int err;
+
+
+ /*
+ * Get buffer for PDU
+ */
+ KB_ALLOCPKT(m, sizeof(struct ustat_pdu), KB_F_NOWAIT, KB_T_HEADER);
+ if (m == NULL)
+ return (1);
+
+ /*
+ * Setup buffer controls
+ */
+ KB_HEADSET(m, MIN(sop->so_headout,
+ KB_BFRLEN(m) - sizeof(struct ustat_pdu)));
+ KB_LEN(m) = sizeof(struct ustat_pdu);
+
+ /*
+ * Build PDU
+ */
+ KB_DATASTART(m, up, struct ustat_pdu *);
+ up->ustat_le1 = htonl(SEQ_VAL(sop->so_rcvhigh));
+ up->ustat_le2 = htonl(SEQ_VAL(ns));
+ up->ustat_nmr = htonl(SEQ_VAL(sop->so_rcvmax));
+ up->ustat_nr =
+ htonl((PT_USTAT << PT_TYPE_SHIFT) | SEQ_VAL(sop->so_rcvnext));
+
+ /*
+ * Send PDU towards peer
+ */
+ STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
+ sop->so_connvc, (int)m, 0, err);
+
+ if (err)
+ KB_FREEALL(m);
+
+ return (err);
+}
+
+
+/*
+ * Build and send UD PDU
+ *
+ * A UD PDU will be constructed and passed down the protocol stack.
+ *
+ * Arguments:
+ * sop pointer to sscop connection control block
+ * m pointer to user data buffer chain
+ *
+ * Returns:
+ * 0 PDU successfully built and passed down the stack
+ * else unable to build or send pdu (buffer released)
+ *
+ */
+int
+sscop_send_ud(sop, m)
+ struct sscop *sop;
+ KBuffer *m;
+{
+ KBuffer *ml, *n;
+ int len = 0, err;
+ int pad, trlen, space;
+ u_char *cp;
+
+ /*
+ * Count data and get to last buffer in chain
+ */
+ for (ml = m; ; ml = KB_NEXT(ml)) {
+ len += KB_LEN(ml);
+ if (KB_NEXT(ml) == NULL)
+ break;
+ }
+
+ /*
+ * Verify data length
+ */
+ if (len > sop->so_parm.sp_maxinfo) {
+ KB_FREEALL(m);
+ sscop_abort(sop, "sscop: maximum unitdata size exceeded\n");
+ return (1);
+ }
+
+ /*
+ * Figure out how much padding we'll need
+ */
+ pad = ((len + (PDU_PAD_ALIGN - 1)) & ~(PDU_PAD_ALIGN - 1)) - len;
+ trlen = pad + sizeof(struct ud_pdu);
+
+ /*
+ * Get space for PDU trailer and padding
+ */
+ KB_TAILROOM(ml, space);
+ if (space < trlen) {
+ /*
+ * Allocate & link buffer for pad and trailer
+ */
+ KB_ALLOC(n, trlen, KB_F_NOWAIT, KB_T_HEADER);
+ if (n == NULL)
+ return (1);
+
+ KB_LEN(n) = 0;
+ KB_LINK(n, ml);
+ ml = n;
+ }
+
+ /*
+ * Build the PDU trailer
+ *
+ * Since we can't be sure of alignment in the buffers, we
+ * have to move this a byte at a time.
+ */
+ KB_DATAEND(ml, cp, u_char *);
+ cp += pad;
+ *cp++ = (pad << PT_PAD_SHIFT) | PT_UD;
+ KM_ZERO(cp, 3);
+ KB_LEN(ml) += trlen;
+
+ /*
+ * Now pass PDU down the stack
+ */
+ STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
+ sop->so_connvc, (int)m, 0, err);
+ if (err) {
+ KB_FREEALL(m);
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * Print an SSCOP PDU
+ *
+ * Arguments:
+ * sop pointer to sscop connection control block
+ * m pointer to pdu buffer chain
+ * msg pointer to message string
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_pdu_print(sop, m, msg)
+ struct sscop *sop;
+ KBuffer *m;
+ char *msg;
+{
+ char buf[128];
+ struct vccb *vcp;
+
+ vcp = sop->so_connvc->cvc_vcc;
+ sprintf(buf, "sscop %s: vcc=(%d,%d)\n", msg, vcp->vc_vpi, vcp->vc_vci);
+ atm_pdu_print(m, buf);
+}
+
diff --git a/sys/netatm/uni/sscop_pdu.h b/sys/netatm/uni/sscop_pdu.h
new file mode 100644
index 0000000..387a602
--- /dev/null
+++ b/sys/netatm/uni/sscop_pdu.h
@@ -0,0 +1,317 @@
+/*
+ *
+ * ===================================
+ * 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: sscop_pdu.h,v 1.3 1997/05/06 22:20:15 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * SSCOP Protocol Data Unit (PDU) definitions
+ *
+ */
+
+#ifndef _UNI_SSCOP_PDU_H
+#define _UNI_SSCOP_PDU_H
+
+/*
+ * SSCOP PDU Constants
+ */
+#define PDU_MIN_LEN 4 /* Minimum PDU length */
+#define PDU_LEN_MASK 3 /* PDU length must be 32-bit aligned */
+#define PDU_ADDR_MASK 3 /* PDUs must be 32-bit aligned */
+#define PDU_SEQ_MASK 0x00ffffff /* Mask for 24-bit sequence values */
+#define PDU_MAX_INFO 65528 /* Maximum length of PDU info field */
+#define PDU_MAX_UU 65524 /* Maximum length of SSCOP-UU field */
+#define PDU_MAX_STAT 65520 /* Maximum length of STAT list */
+#define PDU_MAX_ELEM 67 /* Maximum elements sent in STAT */
+#define PDU_PAD_ALIGN 4 /* I-field padding alignment */
+
+
+/*
+ * PDU Queueing Header
+ *
+ * There will be a queueing header tacked on to the front of each
+ * buffer chain that is placed on any of the sscop SD PDU queues (not
+ * including the SD transmission queue). Note that this header will
+ * not be included in the buffer data length/offset fields.
+ */
+struct pdu_hdr {
+ union {
+ struct pdu_hdr *phu_pack_lk; /* Pending ack queue link */
+ struct pdu_hdr *phu_recv_lk; /* Receive queue link */
+ } ph_u;
+ struct pdu_hdr *ph_rexmit_lk; /* Retranmit queue link */
+ sscop_seq ph_ns; /* SD.N(S) - SD's sequence number */
+ sscop_seq ph_nps; /* SD.N(PS) - SD's poll sequence */
+ KBuffer *ph_buf; /* Pointer to containing buffer */
+};
+#define ph_pack_lk ph_u.phu_pack_lk
+#define ph_recv_lk ph_u.phu_recv_lk
+
+
+/*
+ * SSCOP PDU formats
+ *
+ * N.B. - all SSCOP PDUs are trailer oriented (don't ask me...)
+ */
+
+/*
+ * PDU Type Fields
+ */
+#define PT_PAD_MASK 0xc0 /* Pad length mask */
+#define PT_PAD_SHIFT 6 /* Pad byte shift count */
+#define PT_SOURCE_SSCOP 0x10 /* Source = SSCOP */
+#define PT_TYPE_MASK 0x0f /* Type mask */
+#define PT_TYPE_MAX 0x0f /* Maximum pdu type */
+#define PT_TYPE_SHIFT 24 /* Type word shift count */
+
+#define PT_BGN 0x01 /* Begin */
+#define PT_BGAK 0x02 /* Begin Acknowledge */
+#define PT_BGREJ 0x07 /* Begin Reject */
+#define PT_END 0x03 /* End */
+#define PT_ENDAK 0x04 /* End Acknowledge */
+#define PT_RS 0x05 /* Resynchronization */
+#define PT_RSAK 0x06 /* Resynchronization Acknowledge */
+#define PT_ER 0x09 /* Error Recovery */
+#define PT_ERAK 0x0f /* Error Recovery Acknowledge */
+#define PT_SD 0x08 /* Sequenced Data */
+#define PT_SDP 0x09 /* Sequenced Data with Poll */
+#define PT_POLL 0x0a /* Status Request */
+#define PT_STAT 0x0b /* Solicited Status Response */
+#define PT_USTAT 0x0c /* Unsolicited Status Response */
+#define PT_UD 0x0d /* Unnumbered Data */
+#define PT_MD 0x0e /* Management Data */
+
+/*
+ * Begin PDU
+ */
+struct bgn_pdu {
+ u_char bgn_rsvd[3]; /* Reserved */
+ u_char bgn_nsq; /* N(SQ) */
+ union {
+ u_char bgnu_type; /* PDU type, etc */
+ sscop_seq bgnu_nmr; /* N(MR) */
+ } bgn_u;
+};
+#define bgn_type bgn_u.bgnu_type
+#define bgn_nmr bgn_u.bgnu_nmr
+
+/*
+ * Begin Acknowledge PDU
+ */
+struct bgak_pdu {
+ int bgak_rsvd; /* Reserved */
+ union {
+ u_char bgaku_type; /* PDU type, etc */
+ sscop_seq bgaku_nmr; /* N(MR) */
+ } bgak_u;
+};
+#define bgak_type bgak_u.bgaku_type
+#define bgak_nmr bgak_u.bgaku_nmr
+
+/*
+ * Begin Reject PDU
+ */
+struct bgrej_pdu {
+ int bgrej_rsvd2; /* Reserved */
+ u_char bgrej_type; /* PDU type, etc */
+ u_char bgrej_rsvd1[3]; /* Reserved */
+};
+
+/*
+ * End PDU
+ */
+struct end_pdu {
+ int end_rsvd2; /* Reserved */
+ u_char end_type; /* PDU type, etc */
+ u_char end_rsvd1[3]; /* Reserved */
+};
+
+/*
+ * End Acknowledge PDU (Q.2110)
+ */
+struct endak_q2110_pdu {
+ int endak_rsvd2; /* Reserved */
+ u_char endak_type; /* PDU type, etc */
+ u_char endak_rsvd1[3]; /* Reserved */
+};
+
+/*
+ * End Acknowledge PDU (Q.SAAL)
+ */
+struct endak_qsaal_pdu {
+ u_char endak_type; /* PDU type, etc */
+ u_char endak_rsvd[3]; /* Reserved */
+};
+
+/*
+ * Resynchronization PDU
+ */
+struct rs_pdu {
+ char rs_rsvd[3]; /* Reserved */
+ u_char rs_nsq; /* N(SQ) */
+ union {
+ u_char rsu_type; /* PDU type, etc */
+ sscop_seq rsu_nmr; /* N(MR) */
+ } rs_u;
+};
+#define rs_type rs_u.rsu_type
+#define rs_nmr rs_u.rsu_nmr
+
+/*
+ * Resynchronization Acknowledge PDU (Q.2110)
+ */
+struct rsak_q2110_pdu {
+ int rsak_rsvd; /* Reserved */
+ union {
+ u_char rsaku_type; /* PDU type, etc */
+ sscop_seq rsaku_nmr; /* N(MR) */
+ } rsak_u;
+};
+#define rsak2_type rsak_u.rsaku_type
+#define rsak_nmr rsak_u.rsaku_nmr
+
+/*
+ * Resynchronization Acknowledge PDU (Q.SAAL)
+ */
+struct rsak_qsaal_pdu {
+ u_char rsaks_type; /* PDU type, etc */
+ u_char rsak_rsvd[3]; /* Reserved */
+};
+
+/*
+ * Error Recovery PDU
+ */
+struct er_pdu {
+ char er_rsvd[3]; /* Reserved */
+ u_char er_nsq; /* N(SQ) */
+ union {
+ u_char eru_type; /* PDU type, etc */
+ sscop_seq eru_nmr; /* N(MR) */
+ } er_u;
+};
+#define er_type er_u.eru_type
+#define er_nmr er_u.eru_nmr
+
+/*
+ * Error Recovery Acknowledge PDU
+ */
+struct erak_pdu {
+ int erak_rsvd; /* Reserved */
+ union {
+ u_char eraku_type; /* PDU type, etc */
+ sscop_seq eraku_nmr; /* N(MR) */
+ } erak_u;
+};
+#define erak_type erak_u.eraku_type
+#define erak_nmr erak_u.eraku_nmr
+
+/*
+ * Sequenced Data PDU
+ */
+struct sd_pdu {
+ union {
+ u_char sdu_type; /* PDU type, etc */
+ sscop_seq sdu_ns; /* N(S) */
+ } sd_u;
+};
+#define sd_type sd_u.sdu_type
+#define sd_ns sd_u.sdu_ns
+
+/*
+ * Sequenced Data with Poll PDU
+ */
+struct sdp_pdu {
+ sscop_seq sdp_nps; /* N(PS) */
+ union {
+ u_char sdpu_type; /* PDU type, etc */
+ sscop_seq sdpu_ns; /* N(S) */
+ } sdp_u;
+};
+#define sdp_type sdp_u.sdpu_type
+#define sdp_ns sdp_u.sdpu_ns
+
+/*
+ * Poll PDU
+ */
+struct poll_pdu {
+ sscop_seq poll_nps; /* N(PS) */
+ union {
+ u_char pollu_type; /* PDU type, etc */
+ sscop_seq pollu_ns; /* N(S) */
+ } poll_u;
+};
+#define poll_type poll_u.pollu_type
+#define poll_ns poll_u.pollu_ns
+
+/*
+ * Solicited Status PDU
+ */
+struct stat_pdu {
+ sscop_seq stat_nps; /* N(PS) */
+ sscop_seq stat_nmr; /* N(MR) */
+ union {
+ u_char statu_type; /* PDU type, etc */
+ sscop_seq statu_nr; /* N(R) */
+ } stat_u;
+};
+#define stat_type stat_u.statu_type
+#define stat_nr stat_u.statu_nr
+
+/*
+ * Unsolicited Status PDU
+ */
+struct ustat_pdu {
+ sscop_seq ustat_le1; /* List element 1 */
+ sscop_seq ustat_le2; /* List element 2 */
+ sscop_seq ustat_nmr; /* N(MR) */
+ union {
+ u_char ustatu_type; /* PDU type, etc */
+ sscop_seq ustatu_nr; /* N(R) */
+ } ustat_u;
+};
+#define ustat_type ustat_u.ustatu_type
+#define ustat_nr ustat_u.ustatu_nr
+
+/*
+ * Unit Data PDU
+ */
+struct ud_pdu {
+ u_char ud_type; /* PDU type, etc */
+ u_char ud_rsvd[3]; /* Reserved */
+};
+
+/*
+ * Management Data PDU
+ */
+struct md_pdu {
+ u_char md_type; /* PDU type, etc */
+ u_char md_rsvd[3]; /* Reserved */
+};
+
+#endif /* _UNI_SSCOP_PDU_H */
diff --git a/sys/netatm/uni/sscop_sigaa.c b/sys/netatm/uni/sscop_sigaa.c
new file mode 100644
index 0000000..8f347ce
--- /dev/null
+++ b/sys/netatm/uni/sscop_sigaa.c
@@ -0,0 +1,449 @@
+/*
+ *
+ * ===================================
+ * 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: sscop_sigaa.c,v 1.1 1998/04/07 23:15:11 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * SSCOP Common - Process AA-signals (SAP_SSCOP)
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: sscop_sigaa.c,v 1.1 1998/04/07 23:15:11 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/uni.h>
+#include <netatm/uni/sscop.h>
+#include <netatm/uni/sscop_misc.h>
+#include <netatm/uni/sscop_pdu.h>
+#include <netatm/uni/sscop_var.h>
+
+
+/*
+ * SSCOP_ESTABLISH_REQ / SOS_IDLE Command Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * arg1 pointer to buffer containing SSCOP-UU data
+ * arg2 buffer release parameter
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_estreq_idle(sop, arg1, arg2)
+ struct sscop *sop;
+ int arg1;
+ int arg2;
+{
+
+ /*
+ * We don't support SSCOP-UU data
+ */
+ if (arg1 != SSCOP_UU_NULL)
+ KB_FREEALL((KBuffer *)arg1);
+
+ /*
+ * We currently only support BR=YES
+ */
+ if (arg2 != SSCOP_BR_YES) {
+ sscop_abort(sop, "sscop: BR != YES\n");
+ return;
+ }
+
+ /*
+ * Initialize receiver window
+ */
+ SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin);
+
+ /*
+ * Send first BGN PDU
+ */
+ sop->so_connctl = 1;
+ SEQ_INCR(sop->so_sendconn, 1);
+ (void) sscop_send_bgn(sop, SSCOP_SOURCE_USER);
+
+ /*
+ * Reset transmitter state
+ */
+ if (sop->so_vers == SSCOP_VERS_Q2110)
+ q2110_clear_xmit(sop);
+ else
+ qsaal1_reset_xmit(sop);
+
+ /*
+ * Set retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc;
+
+ /*
+ * Wait for BGAK
+ */
+ sop->so_state = SOS_OUTCONN;
+
+ return;
+}
+
+
+/*
+ * SSCOP_ESTABLISH_RSP / SOS_INCONN Command Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * arg1 pointer to buffer containing SSCOP-UU data
+ * arg2 buffer release parameter
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_estrsp_inconn(sop, arg1, arg2)
+ struct sscop *sop;
+ int arg1;
+ int arg2;
+{
+
+ /*
+ * We don't support SSCOP-UU data
+ */
+ if (arg1 != SSCOP_UU_NULL)
+ KB_FREEALL((KBuffer *)arg1);
+
+ /*
+ * We currently only support BR=YES
+ */
+ if (arg2 != SSCOP_BR_YES) {
+ sscop_abort(sop, "sscop: BR != YES\n");
+ return;
+ }
+
+ if (sop->so_vers == SSCOP_VERS_Q2110) {
+ /*
+ * Clear transmitter buffers
+ */
+ q2110_clear_xmit(sop);
+
+ /*
+ * Initialize state variables
+ */
+ SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin);
+ q2110_init_state(sop);
+ } else {
+ /*
+ * Reset transmitter state
+ */
+ qsaal1_reset_xmit(sop);
+ }
+
+ /*
+ * Send BGAK PDU
+ */
+ (void) sscop_send_bgak(sop);
+
+ /*
+ * Start polling timer
+ */
+ sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll;
+
+ /*
+ * Start lost poll/stat timer
+ */
+ sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
+
+ /*
+ * OK, we're ready for data
+ */
+ sop->so_state = SOS_READY;
+
+ /*
+ * See if transmit queues need servicing
+ */
+ if (sop->so_flags & SOF_XMITSRVC)
+ sscop_service_xmit(sop);
+
+ return;
+}
+
+
+/*
+ * SSCOP_RELEASE_REQ / SOS_OUTCONN Command Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * arg1 pointer to buffer containing SSCOP-UU data
+ * arg2 unused
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_relreq_outconn(sop, arg1, arg2)
+ struct sscop *sop;
+ int arg1;
+ int arg2;
+{
+
+ /*
+ * We don't support SSCOP-UU data
+ */
+ if (arg1 != SSCOP_UU_NULL)
+ KB_FREEALL((KBuffer *)arg1);
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Clear reestablishment flag
+ */
+ sop->so_flags &= ~SOF_REESTAB;
+
+ /*
+ * Send first END PDU
+ */
+ sop->so_connctl = 1;
+ (void) sscop_send_end(sop, SSCOP_SOURCE_USER);
+
+ if (sop->so_vers == SSCOP_VERS_QSAAL)
+ /*
+ * Clear connection data
+ */
+ qsaal1_clear_connection(sop);
+
+ /*
+ * Set retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc;
+
+ /*
+ * Wait for ENDAK
+ */
+ sop->so_state = SOS_OUTDISC;
+
+ return;
+}
+
+
+/*
+ * SSCOP_RELEASE_REQ / SOS_INCONN Command Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * arg1 pointer to buffer containing SSCOP-UU data
+ * arg2 unused
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_relreq_inconn(sop, arg1, arg2)
+ struct sscop *sop;
+ int arg1;
+ int arg2;
+{
+
+ /*
+ * We don't support SSCOP-UU data
+ */
+ if (arg1 != SSCOP_UU_NULL)
+ KB_FREEALL((KBuffer *)arg1);
+
+ /*
+ * Return a BGREJ PDU
+ */
+ (void) sscop_send_bgrej(sop);
+
+ /*
+ * Back to IDLE state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * SSCOP_RELEASE_REQ / SOS_READY Command Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * arg1 pointer to buffer containing SSCOP-UU data
+ * arg2 unused
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_relreq_ready(sop, arg1, arg2)
+ struct sscop *sop;
+ int arg1;
+ int arg2;
+{
+
+ /*
+ * We don't support SSCOP-UU data
+ */
+ if (arg1 != SSCOP_UU_NULL)
+ KB_FREEALL((KBuffer *)arg1);
+
+ /*
+ * Stop data transfer timers
+ */
+ sop->so_timer[SSCOP_T_POLL] = 0;
+ sop->so_timer[SSCOP_T_NORESP] = 0;
+ sop->so_timer[SSCOP_T_IDLE] = 0;
+ sop->so_flags &= ~SOF_KEEPALIVE;
+
+ /*
+ * Send first END PDU
+ */
+ sop->so_connctl = 1;
+ (void) sscop_send_end(sop, SSCOP_SOURCE_USER);
+
+ if (sop->so_vers == SSCOP_VERS_Q2110) {
+ /*
+ * Clear out appropriate queues
+ */
+ if (sop->so_state == SOS_READY)
+ q2110_prep_retrieve(sop);
+ else
+ sscop_rcvr_drain(sop);
+ } else {
+ /*
+ * Clear connection data
+ */
+ qsaal1_clear_connection(sop);
+ }
+
+ /*
+ * Set retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc;
+
+ /*
+ * Wait for ENDAK
+ */
+ sop->so_state = SOS_OUTDISC;
+
+ return;
+}
+
+
+/*
+ * SSCOP_DATA_REQ / SOS_READY Command Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * arg1 pointer to buffer containing assured user data
+ * arg2 unused
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_datreq_ready(sop, arg1, arg2)
+ struct sscop *sop;
+ int arg1;
+ int arg2;
+{
+ KBuffer *m = (KBuffer *)arg1;
+
+ /*
+ * We must have a buffer (even if it contains no data)
+ */
+ if (m == NULL) {
+ sscop_abort(sop, "sscop_datreq_ready: no buffer\n");
+ return;
+ }
+
+ /*
+ * Place data at end of transmission queue
+ */
+ KB_QNEXT(m) = NULL;
+ if (sop->so_xmit_hd == NULL)
+ sop->so_xmit_hd = m;
+ else
+ KB_QNEXT(sop->so_xmit_tl) = m;
+ sop->so_xmit_tl = m;
+
+ /*
+ * Service the transmit queues
+ */
+ sscop_service_xmit(sop);
+
+ return;
+}
+
+
+/*
+ * SSCOP_UNITDATA_REQ / SOS_* Command Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * arg1 pointer to buffer containing unassured user data
+ * arg2 unused
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_udtreq_all(sop, arg1, arg2)
+ struct sscop *sop;
+ int arg1;
+ int arg2;
+{
+ KBuffer *m = (KBuffer *)arg1;
+
+ /*
+ * We must have a buffer (even if it contains no data)
+ */
+ if (m == NULL) {
+ sscop_abort(sop, "sscop_udtreq_all: no buffer\n");
+ return;
+ }
+
+ /*
+ * Send the data in a UD PDU
+ */
+ (void) sscop_send_ud(sop, m);
+
+ return;
+}
+
diff --git a/sys/netatm/uni/sscop_sigcpcs.c b/sys/netatm/uni/sscop_sigcpcs.c
new file mode 100644
index 0000000..a9bf504
--- /dev/null
+++ b/sys/netatm/uni/sscop_sigcpcs.c
@@ -0,0 +1,2311 @@
+/*
+ *
+ * ===================================
+ * 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: sscop_sigcpcs.c,v 1.2 1998/07/24 20:18:09 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * SSCOP Common - Process CPCS-signals (SSCOP PDUs)
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: sscop_sigcpcs.c,v 1.2 1998/07/24 20:18:09 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/uni.h>
+#include <netatm/uni/sscop.h>
+#include <netatm/uni/sscop_misc.h>
+#include <netatm/uni/sscop_pdu.h>
+#include <netatm/uni/sscop_var.h>
+
+
+/*
+ * No-op Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_noop(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ /*
+ * Just free PDU
+ */
+ KB_FREEALL(m);
+
+ return;
+}
+
+
+/*
+ * BGN PDU / SOS_IDLE Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_bgn_idle(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct bgn_pdu *bp = (struct bgn_pdu *)trlr;
+ int err, source;
+
+ if (sop->so_vers == SSCOP_VERS_Q2110) {
+ /*
+ * "Power-up Robustness" option
+ *
+ * Accept BGN regardless of BGN.N(SQ)
+ */
+ sop->so_rcvconn = bp->bgn_nsq;
+
+ } else {
+ /*
+ * If retransmitted BGN, reject it
+ */
+ if (sscop_is_rexmit(sop, bp->bgn_nsq)) {
+ KB_FREEALL(m);
+ (void) sscop_send_bgrej(sop);
+ return;
+ }
+ }
+
+ if (sop->so_vers == SSCOP_VERS_QSAAL) {
+ /*
+ * Get Source value
+ */
+ if (bp->bgn_type & PT_SOURCE_SSCOP)
+ source = SSCOP_SOURCE_SSCOP;
+ else
+ source = SSCOP_SOURCE_USER;
+
+ /*
+ * Reset receiver state variables
+ */
+ qsaal1_reset_rcvr(sop);
+ } else
+ source = 0;
+
+ /*
+ * Set initial transmit window
+ */
+ SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr));
+
+ /*
+ * Pass connection request up to user
+ */
+ STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, (int)m, source, err);
+ if (err) {
+ KB_FREEALL(m);
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Wait for user's response
+ */
+ sop->so_state = SOS_INCONN;
+
+ return;
+}
+
+
+/*
+ * BGN PDU / SOS_OUTDISC Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_bgn_outdisc(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct bgn_pdu *bp = (struct bgn_pdu *)trlr;
+ int err, source;
+
+ /*
+ * If retransmitted BGN, ACK it and send new END
+ */
+ if (sscop_is_rexmit(sop, bp->bgn_nsq)) {
+ KB_FREEALL(m);
+ (void) sscop_send_bgak(sop);
+ (void) sscop_send_end(sop, SSCOP_SOURCE_LAST);
+ return;
+ }
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Initialize transmit window
+ */
+ SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr));
+
+ /*
+ * Notify user of connection termination
+ */
+ STACK_CALL(SSCOP_RELEASE_CNF, sop->so_upper, sop->so_toku,
+ sop->so_connvc, 0, 0, err);
+ if (err) {
+ KB_FREEALL(m);
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ if (sop->so_vers == SSCOP_VERS_QSAAL) {
+ /*
+ * Get Source value
+ */
+ if (bp->bgn_type & PT_SOURCE_SSCOP)
+ source = SSCOP_SOURCE_SSCOP;
+ else
+ source = SSCOP_SOURCE_USER;
+
+ /*
+ * Reset receiver variables
+ */
+ qsaal1_reset_rcvr(sop);
+
+ } else
+ source = 0;
+
+ /*
+ * Tell user about incoming connection
+ */
+ STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, (int)m, source, err);
+ if (err) {
+ KB_FREEALL(m);
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Wait for user's response
+ */
+ sop->so_state = SOS_INCONN;
+
+ return;
+}
+
+
+/*
+ * BGN PDU / SOS_OUTRESYN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_bgn_outresyn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct bgn_pdu *bp = (struct bgn_pdu *)trlr;
+ int err, source;
+
+ /*
+ * If retransmitted BGN, ACK it and send new RS
+ */
+ if (sscop_is_rexmit(sop, bp->bgn_nsq)) {
+ KB_FREEALL(m);
+ (void) sscop_send_bgak(sop);
+ (void) sscop_send_rs(sop);
+ return;
+ }
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Initialize transmit window
+ */
+ SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr));
+
+ if (sop->so_vers == SSCOP_VERS_QSAAL) {
+ /*
+ * Get (possible) Source value
+ */
+ if (bp->bgn_type & PT_SOURCE_SSCOP)
+ source = SSCOP_SOURCE_SSCOP;
+ else
+ source = SSCOP_SOURCE_USER;
+
+ /*
+ * Reset receiver variables
+ */
+ qsaal1_reset_rcvr(sop);
+
+ } else
+ source = SSCOP_SOURCE_USER;
+
+ /*
+ * Notify user of connection termination
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, SSCOP_UU_NULL, source, err);
+ if (err) {
+ KB_FREEALL(m);
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Now tell user of a "new" incoming connection
+ */
+ STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, (int)m, source, err);
+ if (err) {
+ KB_FREEALL(m);
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Wait for user's response
+ */
+ sop->so_state = SOS_INCONN;
+
+ return;
+}
+
+
+/*
+ * BGN PDU / SOS_INRESYN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_bgn_inresyn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct bgn_pdu *bp = (struct bgn_pdu *)trlr;
+ int err, source;
+
+ /*
+ * If retransmitted BGN, oops
+ */
+ if (sscop_is_rexmit(sop, bp->bgn_nsq)) {
+ KB_FREEALL(m);
+ sscop_maa_error(sop, 'B');
+ return;
+ }
+
+ /*
+ * Stop data transfer timers
+ */
+ sop->so_timer[SSCOP_T_POLL] = 0;
+ sop->so_timer[SSCOP_T_NORESP] = 0;
+ sop->so_timer[SSCOP_T_IDLE] = 0;
+ sop->so_flags &= ~SOF_KEEPALIVE;
+
+ /*
+ * Initialize transmit window
+ */
+ SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr));
+
+ if (sop->so_vers == SSCOP_VERS_QSAAL) {
+ /*
+ * Get (possible) Source value
+ */
+ if (bp->bgn_type & PT_SOURCE_SSCOP)
+ source = SSCOP_SOURCE_SSCOP;
+ else
+ source = SSCOP_SOURCE_USER;
+
+ /*
+ * Reset receiver variables
+ */
+ qsaal1_reset_rcvr(sop);
+
+ } else {
+ /*
+ * Stop possible retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Drain receiver queues
+ */
+ sscop_rcvr_drain(sop);
+
+ /*
+ * Tell user current connection has been released
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_USER, err);
+ if (err) {
+ KB_FREEALL(m);
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ source = 0;
+ }
+
+ /*
+ * Tell user of incoming connection
+ */
+ STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, (int)m, source, err);
+ if (err) {
+ KB_FREEALL(m);
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Wait for user's response
+ */
+ sop->so_state = SOS_INCONN;
+
+ return;
+}
+
+
+/*
+ * BGAK PDU / Protocol Error
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_bgak_error(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+
+ /*
+ * Record error condition
+ */
+ sscop_maa_error(sop, 'C');
+ KB_FREEALL(m);
+
+ return;
+}
+
+
+/*
+ * BGAK PDU / SOS_IDLE Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_bgak_idle(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+
+ /*
+ * Record error condition
+ */
+ sscop_bgak_error(sop, m, trlr);
+
+ /*
+ * Return an END to peer
+ */
+ (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
+ return;
+}
+
+
+/*
+ * BGAK PDU / SOS_OUTCONN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_bgak_outconn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct bgak_pdu *bp = (struct bgak_pdu *)trlr;
+ int err;
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Initialize transmit window
+ */
+ SEQ_SET(sop->so_sendmax, ntohl(bp->bgak_nmr));
+
+ /*
+ * Notify user of connection establishment
+ */
+ if (sop->so_flags & SOF_REESTAB) {
+ KB_FREEALL(m);
+ STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
+ if (err) {
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+ sop->so_flags &= ~SOF_REESTAB;
+ } else {
+ STACK_CALL(SSCOP_ESTABLISH_CNF, sop->so_upper, sop->so_toku,
+ sop->so_connvc, (int)m, 0, err);
+ if (err) {
+ KB_FREEALL(m);
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+ }
+
+ if (sop->so_vers == SSCOP_VERS_QSAAL) {
+ /*
+ * Reset receiver variables
+ */
+ qsaal1_reset_rcvr(sop);
+
+ /*
+ * Start polling timer
+ */
+ sscop_set_poll(sop);
+
+ /*
+ * Start lost poll/stat timer
+ */
+ sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
+
+ } else {
+ /*
+ * Initialize state variables
+ */
+ q2110_init_state(sop);
+
+ /*
+ * Start data transfer timers
+ */
+ sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll;
+ sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
+ }
+
+ /*
+ * OK, we're ready for data
+ */
+ sop->so_state = SOS_READY;
+
+ /*
+ * See if transmit queues need servicing
+ */
+ if (sop->so_flags & SOF_XMITSRVC)
+ sscop_service_xmit(sop);
+
+ return;
+}
+
+
+/*
+ * BGREJ PDU / Protocol Error
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_bgrej_error(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+
+ /*
+ * Record error condition
+ */
+ sscop_maa_error(sop, 'D');
+ KB_FREEALL(m);
+ return;
+}
+
+
+/*
+ * BGREJ PDU / SOS_OUTCONN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_bgrej_outconn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ int source, uu, err;
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ if (sop->so_vers == SSCOP_VERS_QSAAL) {
+ /*
+ * Clear reestablishment flag
+ */
+ sop->so_flags &= ~SOF_REESTAB;
+
+ KB_FREEALL(m);
+ m = NULL;
+ uu = SSCOP_UU_NULL;
+ source = SSCOP_SOURCE_SSCOP;
+ } else {
+ uu = (int)m;
+ source = SSCOP_SOURCE_USER;
+ }
+
+ /*
+ * Notify user of connection failure
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, uu, source, err);
+ if (err) {
+ KB_FREEALL(m);
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Back to idle state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * BGREJ PDU / SOS_INCONN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_bgrej_inconn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ int err;
+
+ /*
+ * Report protocol error
+ */
+ sscop_bgrej_error(sop, m, trlr);
+
+ /*
+ * Notify user of connection failure
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
+ if (err) {
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Back to idle state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * BGREJ PDU / SOS_OUTRESYN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_bgrej_outresyn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ int err;
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Report protocol error
+ */
+ sscop_bgrej_error(sop, m, trlr);
+
+ /*
+ * Notify user of connection failure
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
+ if (err) {
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ if (sop->so_vers == SSCOP_VERS_QSAAL) {
+ /*
+ * Clear connection data
+ */
+ qsaal1_clear_connection(sop);
+ }
+
+ /*
+ * Back to idle state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * BGREJ PDU / SOS_READY Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_bgrej_ready(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ int err;
+
+ /*
+ * Stop data transfer timers
+ */
+ sop->so_timer[SSCOP_T_POLL] = 0;
+ sop->so_timer[SSCOP_T_NORESP] = 0;
+ sop->so_timer[SSCOP_T_IDLE] = 0;
+ sop->so_flags &= ~SOF_KEEPALIVE;
+
+ /*
+ * Report protocol error
+ */
+ sscop_bgrej_error(sop, m, trlr);
+
+ /*
+ * Notify user of connection failure
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
+ if (err) {
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ if (sop->so_vers == SSCOP_VERS_QSAAL) {
+ /*
+ * Clear connection data
+ */
+ qsaal1_clear_connection(sop);
+ } else {
+ /*
+ * Clear out appropriate queues
+ */
+ q2110_prep_retrieve(sop);
+ }
+
+ /*
+ * Back to idle state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * END PDU / SOS_IDLE Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_end_idle(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+
+ /*
+ * Free buffers
+ */
+ KB_FREEALL(m);
+
+ /*
+ * Return an ENDAK to peer
+ */
+ (void) sscop_send_endak(sop);
+
+ return;
+}
+
+
+/*
+ * END PDU / SOS_INCONN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_end_inconn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct end_pdu *ep = (struct end_pdu *)trlr;
+ int err, source;
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Acknowledge END
+ */
+ (void) sscop_send_endak(sop);
+
+ /*
+ * Get Source value
+ */
+ if (ep->end_type & PT_SOURCE_SSCOP)
+ source = SSCOP_SOURCE_SSCOP;
+ else
+ source = SSCOP_SOURCE_USER;
+
+ /*
+ * Notify user of connection termination
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, (int)m, source, err);
+ if (err) {
+ KB_FREEALL(m);
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Back to idle state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * END PDU / SOS_OUTDISC Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_end_outdisc(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ int err;
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Release buffers
+ */
+ KB_FREEALL(m);
+
+ /*
+ * Acknowledge END
+ */
+ (void) sscop_send_endak(sop);
+
+ /*
+ * Notify user of connection termination
+ */
+ STACK_CALL(SSCOP_RELEASE_CNF, sop->so_upper, sop->so_toku,
+ sop->so_connvc, 0, 0, err);
+ if (err) {
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Back to idle state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * ENDAK PDU / Protocol Error
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_endak_error(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+
+ /*
+ * Record error condition
+ */
+ sscop_maa_error(sop, 'F');
+ KB_FREEALL(m);
+
+ return;
+}
+
+
+/*
+ * ENDAK PDU / SOS_INCONN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_endak_inconn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ int err;
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Report protocol error
+ */
+ sscop_endak_error(sop, m, trlr);
+
+ /*
+ * Notify user of connection termination
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
+ if (err) {
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Back to idle state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * ENDAK PDU / SOS_OUTDISC Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_endak_outdisc(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ int err;
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Release buffers
+ */
+ KB_FREEALL(m);
+
+ /*
+ * Notify user of connection termination
+ */
+ STACK_CALL(SSCOP_RELEASE_CNF, sop->so_upper, sop->so_toku,
+ sop->so_connvc, 0, 0, err);
+ if (err) {
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Back to idle state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * ENDAK PDU / SOS_READY Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_endak_ready(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ int err;
+
+ /*
+ * Stop data transfer timers
+ */
+ sop->so_timer[SSCOP_T_POLL] = 0;
+ sop->so_timer[SSCOP_T_NORESP] = 0;
+ sop->so_timer[SSCOP_T_IDLE] = 0;
+ sop->so_flags &= ~SOF_KEEPALIVE;
+
+ /*
+ * Report protocol error
+ */
+ sscop_endak_error(sop, m, trlr);
+
+ /*
+ * Notify user of connection failure
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
+ if (err) {
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ if (sop->so_vers == SSCOP_VERS_QSAAL) {
+ /*
+ * Clear connection data
+ */
+ qsaal1_clear_connection(sop);
+ } else {
+ /*
+ * Clear out appropriate queues
+ */
+ q2110_prep_retrieve(sop);
+ }
+
+ /*
+ * Back to idle state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * RS PDU / Protocol Error
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_rs_error(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+
+ /*
+ * Record error condition
+ */
+ sscop_maa_error(sop, 'J');
+ KB_FREEALL(m);
+
+ return;
+}
+
+
+/*
+ * RS PDU / SOS_IDLE Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_rs_idle(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+
+ /*
+ * Report error condition
+ */
+ sscop_rs_error(sop, m, trlr);
+
+ /*
+ * Return an END to peer
+ */
+ (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
+
+ return;
+}
+
+
+/*
+ * RSAK PDU / Protocol Error
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_rsak_error(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+
+ /*
+ * Record error condition
+ */
+ sscop_maa_error(sop, 'K');
+ KB_FREEALL(m);
+
+ return;
+}
+
+
+/*
+ * RSAK PDU / SOS_IDLE Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_rsak_idle(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+
+ /*
+ * Report error condition
+ */
+ sscop_rsak_error(sop, m, trlr);
+
+ /*
+ * Return an END to peer
+ */
+ (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
+ return;
+}
+
+
+/*
+ * RSAK PDU / SOS_OUTRESYN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_rsak_outresyn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct rsak_q2110_pdu *rp = (struct rsak_q2110_pdu *)trlr;
+ int err;
+
+ /*
+ * Stop retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = 0;
+
+ /*
+ * Notify user of resynchronization completion
+ */
+ STACK_CALL(SSCOP_RESYNC_CNF, sop->so_upper, sop->so_toku,
+ sop->so_connvc, 0, 0, err);
+ if (err) {
+ KB_FREEALL(m);
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ if (sop->so_vers == SSCOP_VERS_QSAAL) {
+ /*
+ * Start the polling timer
+ */
+ sscop_set_poll(sop);
+
+ /*
+ * Start lost poll/stat timer
+ */
+ sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
+ } else {
+ /*
+ * Initialize state variables
+ */
+ SEQ_SET(sop->so_sendmax, ntohl(rp->rsak_nmr));
+ q2110_init_state(sop);
+
+ /*
+ * Start data transfer timers
+ */
+ sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll;
+ sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
+ }
+
+ /*
+ * Free buffers
+ */
+ KB_FREEALL(m);
+
+ /*
+ * Now go back to data transfer state
+ */
+ sop->so_state = SOS_READY;
+
+ /*
+ * See if transmit queues need servicing
+ */
+ if (sop->so_flags & SOF_XMITSRVC)
+ sscop_service_xmit(sop);
+
+ return;
+}
+
+
+/*
+ * SD PDU / Protocol Error
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_sd_error(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+
+ /*
+ * Record error condition
+ */
+ sscop_maa_error(sop, 'A');
+ KB_FREEALL(m);
+
+ return;
+}
+
+
+/*
+ * SD PDU / SOS_IDLE Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_sd_idle(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+
+ /*
+ * Record error condition
+ */
+ sscop_sd_error(sop, m, trlr);
+
+ /*
+ * Return an END to peer
+ */
+ (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
+ return;
+}
+
+
+/*
+ * SD PDU / SOS_INCONN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_sd_inconn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ int err;
+
+ /*
+ * Record error condition
+ */
+ sscop_sd_error(sop, m, trlr);
+
+ /*
+ * Return an END to peer
+ */
+ (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
+
+ /*
+ * Notify user of connection failure
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
+ if (err) {
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Go back to idle state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * POLL PDU / Protocol Error
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_poll_error(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+
+ /*
+ * Record error condition
+ */
+ sscop_maa_error(sop, 'G');
+ KB_FREEALL(m);
+
+ return;
+}
+
+
+/*
+ * POLL PDU / SOS_IDLE Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_poll_idle(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+
+ /*
+ * Report error condition
+ */
+ sscop_poll_error(sop, m, trlr);
+
+ /*
+ * Return an END to peer
+ */
+ (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
+ return;
+}
+
+
+/*
+ * POLL PDU / SOS_INCONN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_poll_inconn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ int err;
+
+ /*
+ * Record error condition
+ */
+ sscop_poll_error(sop, m, trlr);
+
+ /*
+ * Return an END to peer
+ */
+ (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
+
+ /*
+ * Notify user of connection failure
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
+ if (err) {
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Go back to idle state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * STAT PDU / Protocol Error
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_stat_error(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+
+ /*
+ * Record error condition
+ */
+ sscop_maa_error(sop, 'H');
+ KB_FREEALL(m);
+
+ return;
+}
+
+
+/*
+ * STAT PDU / SOS_IDLE Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_stat_idle(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+
+ /*
+ * Report error condition
+ */
+ sscop_stat_error(sop, m, trlr);
+
+ /*
+ * Return an END to peer
+ */
+ (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
+ return;
+}
+
+
+/*
+ * STAT PDU / SOS_INCONN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_stat_inconn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ int err;
+
+ /*
+ * Record error condition
+ */
+ sscop_stat_error(sop, m, trlr);
+
+ /*
+ * Return an END to peer
+ */
+ (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
+
+ /*
+ * Notify user of connection failure
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
+ if (err) {
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Go back to idle state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * STAT PDU / SOS_READY Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_stat_ready(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct stat_pdu *sp = (struct stat_pdu *)trlr;
+ struct pdu_hdr *php;
+ KBuffer *m0 = m;
+ sscop_seq seq1, seq2, opa;
+ int cnt = 0;
+
+ NTOHL(sp->stat_nps);
+ NTOHL(sp->stat_nmr);
+ NTOHL(sp->stat_nr);
+
+ /*
+ * Validate peer's received poll sequence number
+ */
+ if (SEQ_GT(sop->so_pollack, sp->stat_nps, sop->so_pollack) ||
+ SEQ_GT(sp->stat_nps, sop->so_pollsend, sop->so_pollack)) {
+ /*
+ * Bad poll sequence number
+ */
+ sscop_maa_error(sop, 'R');
+ goto goterr;
+ }
+
+ /*
+ * Validate peer's current receive data sequence number
+ */
+ if (SEQ_GT(sop->so_ack, sp->stat_nr, sop->so_ack) ||
+ SEQ_GT(sp->stat_nr, sop->so_send, sop->so_ack)) {
+ /*
+ * Bad data sequence number
+ */
+ sscop_maa_error(sop, 'S');
+ goto goterr;
+ }
+
+ /*
+ * Free acknowledged PDUs
+ */
+ for (seq1 = sop->so_ack, SEQ_SET(seq2, sp->stat_nr);
+ SEQ_LT(seq1, seq2, sop->so_ack);
+ SEQ_INCR(seq1, 1)) {
+ sscop_pack_free(sop, seq1);
+ }
+
+ /*
+ * Update transmit state variables
+ */
+ opa = sop->so_pollack;
+ sop->so_ack = seq2;
+ SEQ_SET(sop->so_pollack, sp->stat_nps);
+ SEQ_SET(sop->so_sendmax, sp->stat_nmr);
+
+ /*
+ * Get first element in STAT list
+ */
+ while (m && (KB_LEN(m) == 0))
+ m = KB_NEXT(m);
+ if (m == NULL)
+ goto done;
+ m = sscop_stat_getelem(m, &seq1);
+
+ /*
+ * Make sure there's a second element too
+ */
+ if (m == NULL)
+ goto done;
+
+ /*
+ * Validate first element (start of missing pdus)
+ */
+ if (SEQ_GT(sop->so_ack, seq1, sop->so_ack) ||
+ SEQ_GEQ(seq1, sop->so_send, sop->so_ack)) {
+ /*
+ * Bad element sequence number
+ */
+ sscop_maa_error(sop, 'S');
+ goto goterr;
+ }
+
+ /*
+ * Loop thru all STAT elements in list
+ */
+ while (m) {
+ /*
+ * Get next even element (start of received pdus)
+ */
+ m = sscop_stat_getelem(m, &seq2);
+
+ /*
+ * Validate seqence number
+ */
+ if (SEQ_GEQ(seq1, seq2, sop->so_ack) ||
+ SEQ_GT(seq2, sop->so_send, sop->so_ack)) {
+ /*
+ * Bad element sequence number
+ */
+ sscop_maa_error(sop, 'S');
+ goto goterr;
+ }
+
+ /*
+ * Process each missing sequence number in this gap
+ */
+ while (SEQ_LT(seq1, seq2, sop->so_ack)) {
+ /*
+ * Find corresponding SD PDU on pending ack queue
+ */
+ php = sscop_pack_locate(sop, seq1);
+ if (php == NULL) {
+ sscop_maa_error(sop, 'S');
+ goto goterr;
+ }
+
+ /*
+ * Retransmit this SD PDU only if it was last sent
+ * during an earlier poll sequence and it's not
+ * already scheduled for retranmission.
+ */
+ if (SEQ_LT(php->ph_nps, sp->stat_nps, opa) &&
+ (php->ph_rexmit_lk == NULL) &&
+ (sop->so_rexmit_tl != php)) {
+ /*
+ * Put PDU on retransmit queue and schedule
+ * transmit servicing
+ */
+ sscop_rexmit_insert(sop, php);
+ sop->so_flags |= SOF_XMITSRVC;
+ cnt++;
+ }
+
+ /*
+ * Bump to next sequence number
+ */
+ SEQ_INCR(seq1, 1);
+ }
+
+ /*
+ * Now process series of acknowledged PDUs
+ *
+ * Get next odd element (start of missing pdus),
+ * but make sure there is one and that it's valid
+ */
+ if (m == NULL)
+ goto done;
+ m = sscop_stat_getelem(m, &seq2);
+ if (SEQ_GEQ(seq1, seq2, sop->so_ack) ||
+ SEQ_GT(seq2, sop->so_send, sop->so_ack)) {
+ /*
+ * Bad element sequence number
+ */
+ sscop_maa_error(sop, 'S');
+ goto goterr;
+ }
+
+ /*
+ * Process each acked sequence number
+ */
+ while (SEQ_LT(seq1, seq2, sop->so_ack)) {
+ /*
+ * Can we clear transmit buffers ??
+ */
+ if ((sop->so_flags & SOF_NOCLRBUF) == 0) {
+ /*
+ * Yes, free acked buffers
+ */
+ sscop_pack_free(sop, seq1);
+ }
+
+ /*
+ * Bump to next sequence number
+ */
+ SEQ_INCR(seq1, 1);
+ }
+ }
+
+done:
+ /*
+ * Free PDU buffer chain
+ */
+ KB_FREEALL(m0);
+
+ /*
+ * Report retransmitted PDUs
+ */
+ if (cnt)
+ sscop_maa_error(sop, 'V');
+
+ /*
+ * Record transmit window closed transitions
+ */
+ if (SEQ_LT(sop->so_send, sop->so_sendmax, sop->so_ack)) {
+ if (sop->so_flags & SOF_NOCREDIT) {
+ sop->so_flags &= ~SOF_NOCREDIT;
+ sscop_maa_error(sop, 'X');
+ }
+ } else {
+ if ((sop->so_flags & SOF_NOCREDIT) == 0) {
+ sop->so_flags |= SOF_NOCREDIT;
+ sscop_maa_error(sop, 'W');
+ }
+ }
+
+ if (sop->so_vers == SSCOP_VERS_QSAAL)
+ /*
+ * Restart lost poll/stat timer
+ */
+ sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
+ else {
+ /*
+ * Determine new polling phase
+ */
+ if ((sop->so_timer[SSCOP_T_POLL] != 0) &&
+ ((sop->so_flags & SOF_KEEPALIVE) == 0)) {
+ /*
+ * Remain in active phase - reset NO-RESPONSE timer
+ */
+ sop->so_timer[SSCOP_T_NORESP] =
+ sop->so_parm.sp_timeresp;
+
+ } else if (sop->so_timer[SSCOP_T_IDLE] == 0) {
+ /*
+ * Go from transient to idle phase
+ */
+ sop->so_timer[SSCOP_T_POLL] = 0;
+ sop->so_flags &= ~SOF_KEEPALIVE;
+ sop->so_timer[SSCOP_T_NORESP] = 0;
+ sop->so_timer[SSCOP_T_IDLE] = sop->so_parm.sp_timeidle;
+ }
+ }
+
+ /*
+ * See if transmit queues need servicing
+ */
+ if (sop->so_flags & SOF_XMITSRVC)
+ sscop_service_xmit(sop);
+
+ return;
+
+goterr:
+ /*
+ * Protocol/parameter error encountered
+ */
+
+ /*
+ * Free PDU buffer chain
+ */
+ KB_FREEALL(m0);
+
+ if (sop->so_vers == SSCOP_VERS_QSAAL)
+ /*
+ * Reestablish a new connection
+ */
+ qsaal1_reestablish(sop);
+ else
+ /*
+ * Initiate error recovery
+ */
+ q2110_error_recovery(sop);
+
+ return;
+}
+
+
+/*
+ * USTAT PDU / Protocol Error
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_ustat_error(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+
+ /*
+ * Record error condition
+ */
+ sscop_maa_error(sop, 'I');
+ KB_FREEALL(m);
+
+ return;
+}
+
+
+/*
+ * USTAT PDU / SOS_IDLE Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_ustat_idle(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+
+ /*
+ * Report error condition
+ */
+ sscop_ustat_error(sop, m, trlr);
+
+ /*
+ * Return an END to peer
+ */
+ (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
+ return;
+}
+
+
+/*
+ * USTAT PDU / SOS_INCONN Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_ustat_inconn(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ int err;
+
+ /*
+ * Record error condition
+ */
+ sscop_ustat_error(sop, m, trlr);
+
+ /*
+ * Return an END to peer
+ */
+ (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
+
+ /*
+ * Notify user of connection failure
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
+ if (err) {
+ sscop_abort(sop, "stack memory\n");
+ return;
+ }
+
+ /*
+ * Go back to idle state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * USTAT PDU / SOS_READY Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_ustat_ready(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ struct ustat_pdu *up = (struct ustat_pdu *)trlr;
+ struct pdu_hdr *php;
+ sscop_seq seq1, seq2;
+
+ NTOHL(up->ustat_nmr);
+ NTOHL(up->ustat_nr);
+
+ /*
+ * Validate peer's current receive data sequence number
+ */
+ if (SEQ_GT(sop->so_ack, up->ustat_nr, sop->so_ack) ||
+ SEQ_GEQ(up->ustat_nr, sop->so_send, sop->so_ack)) {
+ /*
+ * Bad data sequence number
+ */
+ goto goterr;
+ }
+
+ /*
+ * Free acknowledged PDUs
+ */
+ for (seq1 = sop->so_ack, SEQ_SET(seq2, up->ustat_nr);
+ SEQ_LT(seq1, seq2, sop->so_ack);
+ SEQ_INCR(seq1, 1)) {
+ sscop_pack_free(sop, seq1);
+ }
+
+ /*
+ * Update transmit state variables
+ */
+ sop->so_ack = seq2;
+ SEQ_SET(sop->so_sendmax, up->ustat_nmr);
+
+ /*
+ * Get USTAT list elements
+ */
+ SEQ_SET(seq1, ntohl(up->ustat_le1));
+ SEQ_SET(seq2, ntohl(up->ustat_le2));
+
+ /*
+ * Validate elements
+ */
+ if (SEQ_GT(sop->so_ack, seq1, sop->so_ack) ||
+ SEQ_GEQ(seq1, seq2, sop->so_ack) ||
+ SEQ_GEQ(seq2, sop->so_send, sop->so_ack)) {
+ /*
+ * Bad element sequence number
+ */
+ goto goterr;
+ }
+
+ /*
+ * Process each missing sequence number in this gap
+ */
+ while (SEQ_LT(seq1, seq2, sop->so_ack)) {
+ /*
+ * Find corresponding SD PDU on pending ack queue
+ */
+ php = sscop_pack_locate(sop, seq1);
+ if (php == NULL) {
+ goto goterr;
+ }
+
+ /*
+ * Retransmit this SD PDU if it's not
+ * already scheduled for retranmission.
+ */
+ if ((php->ph_rexmit_lk == NULL) &&
+ (sop->so_rexmit_tl != php)) {
+ /*
+ * Put PDU on retransmit queue and schedule
+ * transmit servicing
+ */
+ sscop_rexmit_insert(sop, php);
+ sop->so_flags |= SOF_XMITSRVC;
+ }
+
+ /*
+ * Bump to next sequence number
+ */
+ SEQ_INCR(seq1, 1);
+ }
+
+ /*
+ * Report retransmitted PDUs
+ */
+ sscop_maa_error(sop, 'V');
+
+ /*
+ * Free PDU buffer chain
+ */
+ KB_FREEALL(m);
+
+ /*
+ * See if transmit queues need servicing
+ */
+ if (sop->so_flags & SOF_XMITSRVC)
+ sscop_service_xmit(sop);
+
+ return;
+
+goterr:
+ /*
+ * Protocol/parameter error encountered
+ */
+ sscop_maa_error(sop, 'T');
+
+ /*
+ * Free PDU buffer chain
+ */
+ KB_FREEALL(m);
+
+ if (sop->so_vers == SSCOP_VERS_QSAAL)
+ /*
+ * Reestablish a new connection
+ */
+ qsaal1_reestablish(sop);
+ else
+ /*
+ * Initiate error recovery
+ */
+ q2110_error_recovery(sop);
+
+ return;
+}
+
+
+/*
+ * UD PDU / SOS_* Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_ud_all(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+ int err;
+
+ /*
+ * Pass data up to user
+ */
+ STACK_CALL(SSCOP_UNITDATA_IND, sop->so_upper, sop->so_toku,
+ sop->so_connvc, (int)m, 0, err);
+ if (err)
+ KB_FREEALL(m);
+ return;
+}
+
+
+/*
+ * MD PDU / SOS_* Processor
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * m pointer to PDU buffer (without trailer)
+ * trlr pointer to PDU trailer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_md_all(sop, m, trlr)
+ struct sscop *sop;
+ KBuffer *m;
+ caddr_t trlr;
+{
+
+ /*
+ * We don't support MD PDUs
+ */
+ KB_FREEALL(m);
+ return;
+}
+
diff --git a/sys/netatm/uni/sscop_subr.c b/sys/netatm/uni/sscop_subr.c
new file mode 100644
index 0000000..2d01229
--- /dev/null
+++ b/sys/netatm/uni/sscop_subr.c
@@ -0,0 +1,972 @@
+/*
+ *
+ * ===================================
+ * 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: sscop_subr.c,v 1.7 1998/08/26 23:29:19 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * SSCOP - Subroutines
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: sscop_subr.c,v 1.7 1998/08/26 23:29:19 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/uni.h>
+#include <netatm/uni/sscop.h>
+#include <netatm/uni/sscop_misc.h>
+#include <netatm/uni/sscop_pdu.h>
+#include <netatm/uni/sscop_var.h>
+
+
+/*
+ * Local functions
+ */
+static int sscop_proc_xmit __P((struct sscop *));
+
+
+/*
+ * Get Next Element from STAT PDU
+ *
+ * Arguments:
+ * m pointer to current buffer in STAT PDU
+ * pelem pointer to location to store element value
+ *
+ * Returns:
+ * addr pointer to updated current buffer in STAT PDU
+ *
+ */
+KBuffer *
+sscop_stat_getelem(m, pelem)
+ KBuffer *m;
+ sscop_seq *pelem;
+{
+ caddr_t cp;
+
+ /*
+ * Get to start of element
+ *
+ * Note that we always ensure that the current buffer has
+ * at least one byte of the next element.
+ */
+ KB_DATASTART(m, cp, caddr_t);
+
+ /*
+ * See how much of element is in this buffer
+ */
+ if (KB_LEN(m) >= sizeof(sscop_seq)) {
+ /*
+ * Get element from this buffer
+ */
+ if ((int)cp & (sizeof(sscop_seq) - 1))
+ KM_COPY(cp, (caddr_t)pelem, sizeof(sscop_seq));
+ else
+ *pelem = *(sscop_seq *)cp;
+
+ /*
+ * Update buffer controls
+ */
+ KB_HEADADJ(m, -sizeof(sscop_seq));
+ } else {
+ /*
+ * Get element split between two buffers
+ */
+ int i, j;
+
+ /*
+ * Copy what's in this buffer
+ */
+ i = KB_LEN(m);
+ KM_COPY(cp, (caddr_t)pelem, i);
+ KB_LEN(m) = 0;
+
+ /*
+ * Now get to next buffer
+ */
+ while (m && (KB_LEN(m) == 0))
+ m = KB_NEXT(m);
+
+ /*
+ * And copy remainder of element
+ */
+ j = sizeof(sscop_seq) - i;
+ KB_DATASTART(m, cp, caddr_t);
+ KM_COPY(cp, (caddr_t)pelem + i, j);
+
+ /*
+ * Update buffer controls
+ */
+ KB_HEADADJ(m, -j);
+ }
+
+ /*
+ * Put element (sequence number) into host order
+ */
+ NTOHL(*pelem);
+
+ /*
+ * Get pointers set for next call
+ */
+ while (m && (KB_LEN(m) == 0))
+ m = KB_NEXT(m);
+
+ return (m);
+}
+
+
+/*
+ * Locate SD PDU on Pending Ack Queue
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * seq sequence number of PDU to locate
+ *
+ * Returns:
+ * addr pointer to located PDU header
+ * 0 SD PDU sequence number not found
+ *
+ */
+struct pdu_hdr *
+sscop_pack_locate(sop, seq)
+ struct sscop *sop;
+ sscop_seq seq;
+{
+ struct pdu_hdr *php;
+
+ /*
+ * Loop thru queue until we either find the PDU or the queue's
+ * sequence numbers are greater than the PDU's sequence number,
+ * indicating that the PDU is not on the queue.
+ */
+ for (php = sop->so_pack_hd; php; php = php->ph_pack_lk) {
+ if (php->ph_ns == seq)
+ break;
+
+ if (SEQ_GT(php->ph_ns, seq, sop->so_ack)) {
+ php = NULL;
+ break;
+ }
+ }
+
+ return (php);
+}
+
+
+/*
+ * Free Acknowledged SD PDU
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * seq sequence number of PDU to free
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_pack_free(sop, seq)
+ struct sscop *sop;
+ sscop_seq seq;
+{
+ struct pdu_hdr *php, *prev;
+
+ /*
+ * Unlink PDU from pending ack queue
+ *
+ * First, check for an empty queue
+ */
+ php = sop->so_pack_hd;
+ if (php == NULL)
+ return;
+
+ /*
+ * Now check for PDU at head of queue
+ */
+ if (php->ph_ns == seq) {
+ if ((sop->so_pack_hd = php->ph_pack_lk) == NULL)
+ sop->so_pack_tl = NULL;
+ goto found;
+ }
+
+ /*
+ * Otherwise, loop thru queue until we either find the PDU or
+ * the queue's sequence numbers are greater than the PDU's
+ * sequence number, indicating that the PDU is not on the queue.
+ */
+ prev = php;
+ php = php->ph_pack_lk;
+ while (php) {
+ if (php->ph_ns == seq) {
+ if ((prev->ph_pack_lk = php->ph_pack_lk) == NULL)
+ sop->so_pack_tl = prev;
+ goto found;
+ }
+
+ if (SEQ_GT(php->ph_ns, seq, sop->so_ack))
+ return;
+
+ prev = php;
+ php = php->ph_pack_lk;
+ }
+
+ return;
+
+found:
+ /*
+ * We've got the ack'ed PDU - unlink it from retransmit queue
+ */
+ sscop_rexmit_unlink(sop, php);
+
+ /*
+ * Free PDU buffers
+ */
+ KB_FREEALL(php->ph_buf);
+
+ return;
+}
+
+
+/*
+ * Insert SD PDU into Retransmit Queue
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * php pointer to SD PDU header
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_rexmit_insert(sop, php)
+ struct sscop *sop;
+ struct pdu_hdr *php;
+{
+ struct pdu_hdr *curr, *next;
+ sscop_seq seq = php->ph_ns;
+
+ /*
+ * Check for an empty queue
+ */
+ if ((curr = sop->so_rexmit_hd) == NULL) {
+ php->ph_rexmit_lk = NULL;
+ sop->so_rexmit_hd = php;
+ sop->so_rexmit_tl = php;
+ return;
+ }
+
+ /*
+ * Now see if PDU belongs at head of queue
+ */
+ if (SEQ_LT(seq, curr->ph_ns, sop->so_ack)) {
+ php->ph_rexmit_lk = curr;
+ sop->so_rexmit_hd = php;
+ return;
+ }
+
+ /*
+ * Otherwise, loop thru the queue until we find the
+ * proper insertion point for the PDU
+ */
+ while (next = curr->ph_rexmit_lk) {
+ if (SEQ_LT(seq, next->ph_ns, sop->so_ack)) {
+ php->ph_rexmit_lk = next;
+ curr->ph_rexmit_lk = php;
+ return;
+ }
+ curr = next;
+ }
+
+ /*
+ * Insert PDU at end of queue
+ */
+ php->ph_rexmit_lk = NULL;
+ curr->ph_rexmit_lk = php;
+ sop->so_rexmit_tl = php;
+
+ return;
+}
+
+
+/*
+ * Unlink SD PDU from Retransmit Queue
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * php pointer to PDU header to unlink
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_rexmit_unlink(sop, php)
+ struct sscop *sop;
+ struct pdu_hdr *php;
+{
+ struct pdu_hdr *curr;
+
+ /*
+ * See if PDU is on retransmit queue
+ */
+ if ((php->ph_rexmit_lk == NULL) && (sop->so_rexmit_tl != php))
+ return;
+
+ /*
+ * It's here somewhere, so first check for the PDU at the
+ * head of the queue
+ */
+ if (php == sop->so_rexmit_hd) {
+ if ((sop->so_rexmit_hd = php->ph_rexmit_lk) == NULL)
+ sop->so_rexmit_tl = NULL;
+ php->ph_rexmit_lk = NULL;
+ return;
+ }
+
+ /*
+ * Otherwise, loop thru the queue until we find the PDU
+ */
+ for (curr = sop->so_rexmit_hd; curr; curr = curr->ph_rexmit_lk) {
+ if (curr->ph_rexmit_lk == php)
+ break;
+ }
+ if (curr) {
+ if ((curr->ph_rexmit_lk = php->ph_rexmit_lk) == NULL)
+ sop->so_rexmit_tl = curr;
+ } else {
+ log(LOG_ERR,
+ "sscop_rexmit_unlink: Not found - sop=0x%x, php=0x%x\n",
+ (int)sop, (int)php);
+#ifdef DIAGNOSTIC
+ panic("sscop_rexmit_unlink: Not found");
+#endif
+ }
+ php->ph_rexmit_lk = NULL;
+
+ return;
+}
+
+
+/*
+ * Drain Transmission Queues
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_xmit_drain(sop)
+ struct sscop *sop;
+{
+ KBuffer *m;
+ struct pdu_hdr *php;
+
+ /*
+ * Free transmission queue buffers
+ */
+ while (m = sop->so_xmit_hd) {
+ sop->so_xmit_hd = KB_QNEXT(m);
+ KB_FREEALL(m);
+ }
+ sop->so_xmit_tl = NULL;
+
+ /*
+ * Free retransmission queue
+ *
+ * All retranmission buffers are also on the pending ack
+ * queue (but not the converse), so we just clear the queue
+ * pointers here and do all the real work below.
+ */
+ sop->so_rexmit_hd = NULL;
+ sop->so_rexmit_tl = NULL;
+
+ /*
+ * Free pending ack queue buffers
+ */
+ while (php = sop->so_pack_hd) {
+ sop->so_pack_hd = php->ph_pack_lk;
+ KB_FREEALL(php->ph_buf);
+ }
+ sop->so_pack_tl = NULL;
+
+ /*
+ * Clear service required flag
+ */
+ sop->so_flags &= ~SOF_XMITSRVC;
+
+ return;
+}
+
+
+/*
+ * Insert SD PDU into Receive Queue
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * php pointer to SD PDU header
+ *
+ * Returns:
+ * 0 PDU successfully inserted into queue
+ * 1 duplicate sequence number PDU on queue, PDU not inserted
+ *
+ */
+int
+sscop_recv_insert(sop, php)
+ struct sscop *sop;
+ struct pdu_hdr *php;
+{
+ struct pdu_hdr *curr, *next;
+ sscop_seq seq = php->ph_ns;
+
+ /*
+ * Check for an empty queue
+ */
+ if ((curr = sop->so_recv_hd) == NULL) {
+ php->ph_recv_lk = NULL;
+ sop->so_recv_hd = php;
+ sop->so_recv_tl = php;
+ return (0);
+ }
+
+ /*
+ * Now see if PDU belongs at head of queue
+ */
+ if (SEQ_LT(seq, curr->ph_ns, sop->so_rcvnext)) {
+ php->ph_recv_lk = curr;
+ sop->so_recv_hd = php;
+ return (0);
+ }
+
+ /*
+ * Otherwise, loop thru the queue until we find the
+ * proper insertion point for the PDU. We also check
+ * to make sure there isn't a PDU already on the queue
+ * with a matching sequence number.
+ */
+ while (next = curr->ph_recv_lk) {
+ if (SEQ_LT(seq, next->ph_ns, sop->so_rcvnext)) {
+ if (seq == curr->ph_ns)
+ return (1);
+ php->ph_recv_lk = next;
+ curr->ph_recv_lk = php;
+ return (0);
+ }
+ curr = next;
+ }
+
+ /*
+ * Insert PDU at end of queue
+ */
+ if (seq == curr->ph_ns)
+ return (1);
+ php->ph_recv_lk = NULL;
+ curr->ph_recv_lk = php;
+ sop->so_recv_tl = php;
+
+ return (0);
+}
+
+
+/*
+ * Drain Receiver Queues
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_rcvr_drain(sop)
+ struct sscop *sop;
+{
+ struct pdu_hdr *php;
+
+ /*
+ * Free receive queue buffers
+ */
+ while (php = sop->so_recv_hd) {
+ sop->so_recv_hd = php->ph_recv_lk;
+ KB_FREEALL(php->ph_buf);
+ }
+ sop->so_recv_tl = NULL;
+
+ return;
+}
+
+
+/*
+ * Service connection's transmit queues
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_service_xmit(sop)
+ struct sscop *sop;
+{
+ KBuffer *m, *n;
+ struct pdu_hdr *php;
+ int err = 0, pollsent = 0;
+
+ /*
+ * Initially assume we need service
+ */
+ sop->so_flags |= SOF_XMITSRVC;
+
+ /*
+ * Loop until done with queues
+ *
+ * (Congestion control will be added later)
+ */
+ while (1) {
+ if (php = sop->so_rexmit_hd) {
+
+ /*
+ * Send SD PDU from retransmit queue
+ *
+ * First, get a copy of the PDU to send
+ */
+ m = php->ph_buf;
+ if (KB_LEN(m) == 0)
+ m = KB_NEXT(m);
+ KB_COPY(m, 0, KB_COPYALL, n, KB_F_NOWAIT);
+ if (n == NULL) {
+ err = 1;
+ break;
+ }
+
+ /*
+ * Now pass it down the stack
+ */
+ STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower,
+ sop->so_tokl, sop->so_connvc, (int)n, 0, err);
+ if (err) {
+ KB_FREEALL(n);
+ break;
+ }
+
+ /*
+ * PDU is on its way, so remove it from
+ * the retransmit queue
+ */
+ if (sop->so_rexmit_tl == php) {
+ sop->so_rexmit_hd = NULL;
+ sop->so_rexmit_tl = NULL;
+ } else {
+ sop->so_rexmit_hd = php->ph_rexmit_lk;
+ }
+ php->ph_rexmit_lk = NULL;
+
+ /*
+ * Update PDU's poll sequence
+ */
+ php->ph_nps = sop->so_pollsend;
+
+ } else if (sop->so_xmit_hd) {
+
+ /*
+ * Newly arrived data waiting to be sent.
+ * See if transmit window allows us to send it.
+ */
+ if (SEQ_LT(sop->so_send, sop->so_sendmax, sop->so_ack)){
+ /*
+ * OK, send SD PDU from transmission queue
+ */
+ err = sscop_proc_xmit(sop);
+ if (err)
+ break;
+ } else {
+ /*
+ * Can't send now, so leave idle phase.
+ */
+ if (sop->so_timer[SSCOP_T_IDLE] != 0) {
+ sop->so_timer[SSCOP_T_IDLE] = 0;
+ sop->so_timer[SSCOP_T_NORESP] =
+ sop->so_parm.sp_timeresp;
+ err = 1;
+ }
+ break;
+ }
+
+ } else {
+
+ /*
+ * We're finished, so clear service required flag
+ */
+ sop->so_flags &= ~SOF_XMITSRVC;
+ break;
+ }
+
+ /*
+ * We've sent another SD PDU
+ */
+ sop->so_polldata++;
+
+ /*
+ * Transition into active (polling) phase
+ */
+ if (sop->so_timer[SSCOP_T_POLL] != 0) {
+ if (sop->so_flags & SOF_KEEPALIVE) {
+ /*
+ * Leaving transient phase
+ */
+ sop->so_flags &= ~SOF_KEEPALIVE;
+ sop->so_timer[SSCOP_T_POLL] =
+ sop->so_parm.sp_timepoll;
+ }
+ } else {
+ /*
+ * Leaving idle phase
+ */
+ sop->so_timer[SSCOP_T_IDLE] = 0;
+ sop->so_timer[SSCOP_T_NORESP] =
+ sop->so_parm.sp_timeresp;
+ sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll;
+ }
+
+ /*
+ * Let's see if we need to send a POLL yet
+ */
+ if (sop->so_polldata < sop->so_parm.sp_maxpd)
+ continue;
+
+ /*
+ * Yup, send another poll out
+ */
+ SEQ_INCR(sop->so_pollsend, 1);
+ (void) sscop_send_poll(sop);
+ pollsent++;
+
+ /*
+ * Reset data counter for this poll cycle
+ */
+ sop->so_polldata = 0;
+
+ /*
+ * Restart polling timer in active phase
+ */
+ sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll;
+ }
+
+ /*
+ * If we need/want to send a poll, but haven't sent any yet
+ * on this servicing, send one now
+ */
+ if (err && (pollsent == 0)) {
+ /*
+ * Send poll
+ */
+ SEQ_INCR(sop->so_pollsend, 1);
+ (void) sscop_send_poll(sop);
+
+ /*
+ * Reset data counter for this poll cycle
+ */
+ sop->so_polldata = 0;
+
+ /*
+ * Restart polling timer in active phase
+ */
+ sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll;
+ sop->so_flags &= ~SOF_KEEPALIVE;
+ }
+
+ return;
+}
+
+
+/*
+ * Process Transmission Queue PDU
+ *
+ * For the first entry on the transmission queue: add a PDU header and
+ * trailer, send a copy of the PDU down the stack and move the PDU from
+ * the transmission queue to the pending ack queue.
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ *
+ * Returns:
+ * 0 head of transmission queue successfully processed
+ * else processing error, tranmission queue unchanged
+ *
+ */
+static int
+sscop_proc_xmit(sop)
+ struct sscop *sop;
+{
+ KBuffer *m, *ml, *n;
+ struct pdu_hdr *php;
+ sscop_seq seq;
+ int len = 0, err;
+ int pad, trlen, space;
+ u_char *cp;
+
+ /*
+ * Get first buffer chain on queue
+ */
+ if ((m = sop->so_xmit_hd) == NULL)
+ return (0);
+
+ /*
+ * Count data and get to last buffer in chain
+ */
+ for (ml = m; ; ml = KB_NEXT(ml)) {
+ len += KB_LEN(ml);
+ if (KB_NEXT(ml) == NULL)
+ break;
+ }
+
+ /*
+ * Verify data length
+ */
+ if (len > sop->so_parm.sp_maxinfo) {
+ sscop_abort(sop, "sscop: maximum data size exceeded\n");
+ return (1);
+ }
+
+ /*
+ * Get space for PDU header
+ */
+ KB_HEADROOM(m, space);
+ if (space < sizeof(struct pdu_hdr)) {
+ /*
+ * Allocate & link buffer for header
+ */
+ KB_ALLOC(n, sizeof(struct pdu_hdr), KB_F_NOWAIT, KB_T_HEADER);
+ if (n == NULL)
+ return (1);
+
+ KB_LEN(n) = 0;
+ KB_HEADSET(n, sizeof(struct pdu_hdr));
+ KB_LINKHEAD(n, m);
+ KB_QNEXT(n) = KB_QNEXT(m);
+ KB_QNEXT(m) = NULL;
+ sop->so_xmit_hd = n;
+ if (sop->so_xmit_tl == m)
+ sop->so_xmit_tl = n;
+ m = n;
+ }
+
+ /*
+ * Figure out how much padding we'll need
+ */
+ pad = ((len + (PDU_PAD_ALIGN - 1)) & ~(PDU_PAD_ALIGN - 1)) - len;
+ trlen = pad + sizeof(struct sd_pdu);
+
+ /*
+ * Now get space for PDU trailer and padding
+ */
+ KB_TAILROOM(ml, space);
+ if (space < trlen) {
+ /*
+ * Allocate & link buffer for pad and trailer
+ */
+ KB_ALLOC(n, trlen, KB_F_NOWAIT, KB_T_HEADER);
+ if (n == NULL)
+ return (1);
+
+ KB_LEN(n) = 0;
+ KB_LINK(n, ml);
+ ml = n;
+ }
+
+ /*
+ * Build the PDU trailer
+ *
+ * Since we can't be sure of alignment in the buffers, we
+ * have to move this a byte at a time and we have to be
+ * careful with host byte order issues.
+ */
+ KB_DATASTART(ml, cp, u_char *);
+ cp += KB_LEN(ml) + pad;
+ *cp++ = (pad << PT_PAD_SHIFT) | PT_SD;
+ seq = sop->so_send;
+ *(cp + 2) = (u_char)(seq & 0xff);
+ seq >>= 8;
+ *(cp + 1) = (u_char)(seq & 0xff);
+ seq >>= 8;
+ *(cp) = (u_char)(seq & 0xff);
+ KB_LEN(ml) += trlen;
+
+ /*
+ * Get a copy of the SD PDU to send
+ */
+ if (KB_LEN(m) == 0)
+ n = KB_NEXT(m);
+ else
+ n = m;
+ KB_COPY(n, 0, KB_COPYALL, n, KB_F_NOWAIT);
+ if (n == NULL) {
+ KB_LEN(ml) -= trlen;
+ return (1);
+ }
+
+ /*
+ * Now pass copy down the stack
+ */
+ STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
+ sop->so_connvc, (int)n, 0, err);
+ if (err) {
+ KB_FREEALL(n);
+ KB_LEN(ml) -= trlen;
+ return (1);
+ }
+
+ /*
+ * PDU is on its way, so remove buffer from
+ * the transmission queue
+ */
+ if (sop->so_xmit_tl == m) {
+ sop->so_xmit_hd = NULL;
+ sop->so_xmit_tl = NULL;
+ } else {
+ sop->so_xmit_hd = KB_QNEXT(m);
+ }
+ KB_QNEXT(m) = NULL;
+
+ /*
+ * Build PDU header
+ *
+ * We can at least assume/require that the start of
+ * the user data is aligned. Also note that we don't
+ * include this header in the buffer len/offset fields.
+ */
+ KB_DATASTART(m, php, struct pdu_hdr *);
+ php--;
+ php->ph_ns = sop->so_send;
+ php->ph_nps = sop->so_pollsend;
+ php->ph_buf = m;
+ php->ph_rexmit_lk = NULL;
+ php->ph_pack_lk = NULL;
+
+ /*
+ * Put PDU onto the pending ack queue
+ */
+ if (sop->so_pack_hd == NULL)
+ sop->so_pack_hd = php;
+ else
+ sop->so_pack_tl->ph_pack_lk = php;
+ sop->so_pack_tl = php;
+
+ /*
+ * Finally, bump send sequence number
+ */
+ SEQ_INCR(sop->so_send, 1);
+
+ return (0);
+}
+
+
+/*
+ * Detect Retransmitted PDUs
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ * nsq connection sequence value (N(SQ)) from received PDU
+ *
+ * Returns:
+ * 0 received PDU was NOT retransmitted
+ * 1 received PDU was retransmitted
+ *
+ */
+int
+sscop_is_rexmit(sop, nsq)
+ struct sscop *sop;
+ u_char nsq;
+{
+
+ /*
+ * For Q.SAAL1, N(SQ) doesn't exist
+ */
+ if (sop->so_vers == SSCOP_VERS_QSAAL)
+ return (0);
+
+ /*
+ * If we've already received the N(SQ) value,
+ * then this PDU has been retransmitted
+ */
+ if (nsq == sop->so_rcvconn)
+ return (1);
+
+ /*
+ * New PDU, save its N(SQ)
+ */
+ sop->so_rcvconn = nsq;
+
+ return (0);
+}
+
+
+/*
+ * Start connection poll timer
+ *
+ * Arguments:
+ * sop pointer to sscop connection block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_set_poll(sop)
+ struct sscop *sop;
+{
+
+ /*
+ * Decide which polling timer value to set
+ */
+ if ((sop->so_xmit_hd != NULL) || SEQ_NEQ(sop->so_send, sop->so_ack)) {
+ /*
+ * Data outstanding, poll frequently
+ */
+ sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll;
+ sop->so_flags &= ~SOF_KEEPALIVE;
+ } else {
+ /*
+ * No data outstanding, just poll occassionally
+ */
+ sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timekeep;
+ sop->so_flags |= SOF_KEEPALIVE;
+ }
+
+ return;
+}
+
diff --git a/sys/netatm/uni/sscop_timer.c b/sys/netatm/uni/sscop_timer.c
new file mode 100644
index 0000000..8c23344b
--- /dev/null
+++ b/sys/netatm/uni/sscop_timer.c
@@ -0,0 +1,576 @@
+/*
+ *
+ * ===================================
+ * 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: sscop_timer.c,v 1.6 1998/04/07 23:21:48 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * SSCOP - Timer processing
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: sscop_timer.c,v 1.6 1998/04/07 23:21:48 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/uni.h>
+#include <netatm/uni/sscop.h>
+#include <netatm/uni/sscop_misc.h>
+#include <netatm/uni/sscop_pdu.h>
+#include <netatm/uni/sscop_var.h>
+
+
+/*
+ * Local functions
+ */
+static void sscop_poll_expire __P((struct sscop *));
+static void sscop_noresponse_expire __P((struct sscop *));
+static void sscop_cc_expire __P((struct sscop *));
+static void sscop_idle_expire __P((struct sscop *));
+
+/*
+ * Local variables
+ */
+static void (*sscop_expired[SSCOP_T_NUM]) __P((struct sscop *)) = {
+ sscop_poll_expire,
+ sscop_noresponse_expire,
+ sscop_cc_expire,
+ sscop_idle_expire
+};
+
+
+/*
+ * Process an SSCOP timer tick
+ *
+ * This function is called SSCOP_HZ times a second in order to update
+ * all of the sscop connection timers. The sscop expiration function
+ * will be called to process all timer expirations.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * tip pointer to sscop timer control block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_timeout(tip)
+ struct atm_time *tip;
+{
+ struct sscop *sop, **sprev;
+ int i;
+
+
+ /*
+ * Schedule next timeout
+ */
+ atm_timeout(&sscop_timer, ATM_HZ/SSCOP_HZ, sscop_timeout);
+
+ /*
+ * Run through all connections, updating each active timer.
+ * If an expired timer is found, notify that entry.
+ */
+ sprev = &sscop_head;
+ while (sop = *sprev) {
+
+ /*
+ * Check out each timer
+ */
+ for (i =0; i < SSCOP_T_NUM; i++) {
+
+ /*
+ * Decrement timer if it's active
+ */
+ if (sop->so_timer[i] && (--sop->so_timer[i] == 0)) {
+
+#ifdef DIAGNOSTIC
+ {
+ static char *tn[] = {
+ "POLL",
+ "NORESPONSE",
+ "CC",
+ "IDLE"
+ };
+ ATM_DEBUG3("sscop_timer: %s expired, sop=0x%x, state=%d\n",
+ tn[i], (int)sop, sop->so_state);
+ }
+#endif
+
+ /*
+ * Expired timer - process it
+ */
+ (*sscop_expired[i])(sop);
+
+ /*
+ * Make sure connection still exists
+ */
+ if (*sprev != sop)
+ break;
+ }
+ }
+
+ /*
+ * Update previous pointer if current control
+ * block wasn't deleted
+ */
+ if (*sprev == sop)
+ sprev = &sop->so_next;
+ }
+}
+
+
+/*
+ * Process an SSCOP Timer_POLL expiration
+ *
+ * Arguments:
+ * sop pointer to sscop connection control block
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_poll_expire(sop)
+ struct sscop *sop;
+{
+
+ /*
+ * Validate current state
+ */
+ if ((sop->so_state != SOS_READY) &&
+ ((sop->so_state != SOS_INRESYN) ||
+ (sop->so_vers != SSCOP_VERS_QSAAL))) {
+ log(LOG_ERR, "sscop: invalid %s state: sop=0x%x, state=%d\n",
+ "Timer_POLL", (int)sop, sop->so_state);
+ return;
+ }
+
+ /*
+ * Send next poll along its way
+ */
+ SEQ_INCR(sop->so_pollsend, 1);
+ (void) sscop_send_poll(sop);
+
+ /*
+ * Reset data counter for this poll cycle
+ */
+ sop->so_polldata = 0;
+
+ /*
+ * Reset polling timer
+ */
+ sscop_set_poll(sop);
+
+ return;
+}
+
+
+/*
+ * Process an SSCOP Timer_IDLE expiration
+ *
+ * Arguments:
+ * sop pointer to sscop connection control block
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_idle_expire(sop)
+ struct sscop *sop;
+{
+
+ /*
+ * Timer_IDLE only valid in READY state
+ */
+ if (sop->so_state != SOS_READY) {
+ log(LOG_ERR, "sscop: invalid %s state: sop=0x%x, state=%d\n",
+ "Timer_IDLE", (int)sop, sop->so_state);
+ return;
+ }
+
+ /*
+ * Send next poll along its way
+ */
+ SEQ_INCR(sop->so_pollsend, 1);
+ (void) sscop_send_poll(sop);
+
+ /*
+ * Reset data counter for this poll cycle
+ */
+ sop->so_polldata = 0;
+
+ /*
+ * Start NO-RESPONSE timer
+ */
+ sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
+
+ /*
+ * Reset polling timer
+ */
+ sscop_set_poll(sop);
+
+ return;
+}
+
+
+/*
+ * Process an SSCOP Timer_NORESPONSE expiration
+ *
+ * Arguments:
+ * sop pointer to sscop connection control block
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_noresponse_expire(sop)
+ struct sscop *sop;
+{
+ int err;
+
+ /*
+ * Validate current state
+ */
+ if ((sop->so_state != SOS_READY) &&
+ ((sop->so_state != SOS_INRESYN) ||
+ (sop->so_vers != SSCOP_VERS_QSAAL))) {
+ log(LOG_ERR, "sscop: invalid %s state: sop=0x%x, state=%d\n",
+ "Timer_NORESPONSE", (int)sop, sop->so_state);
+ return;
+ }
+
+ /*
+ * Peer seems to be dead, so terminate session
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper,
+ sop->so_toku, sop->so_connvc,
+ SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
+ if (err) {
+ /*
+ * Error, force retry
+ */
+ sop->so_timer[SSCOP_T_NORESP] = 1;
+ return;
+ }
+
+ /*
+ * Stop data transfer timers
+ */
+ sop->so_timer[SSCOP_T_POLL] = 0;
+ sop->so_timer[SSCOP_T_IDLE] = 0;
+ sop->so_flags &= ~SOF_KEEPALIVE;
+
+ /*
+ * Notify peer of termination
+ */
+ (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
+
+ /*
+ * Report peer's failure
+ */
+ sscop_maa_error(sop, 'P');
+
+ if (sop->so_vers == SSCOP_VERS_QSAAL)
+ /*
+ * Clear connection data
+ */
+ qsaal1_clear_connection(sop);
+ else
+ /*
+ * Clear out appropriate queues
+ */
+ q2110_prep_retrieve(sop);
+
+ /*
+ * Return to IDLE state
+ */
+ sop->so_state = SOS_IDLE;
+
+ return;
+}
+
+
+/*
+ * Process an SSCOP Timer_CC expiration
+ *
+ * Arguments:
+ * sop pointer to sscop connection control block
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+sscop_cc_expire(sop)
+ struct sscop *sop;
+{
+ int err;
+
+ /*
+ * Process timeout based on protocol state
+ */
+ switch (sop->so_state) {
+
+ case SOS_OUTCONN:
+ /*
+ * No response to our BGN yet
+ */
+ if (sop->so_connctl < sop->so_parm.sp_maxcc) {
+
+ /*
+ * Send another BGN PDU
+ */
+ sop->so_connctl++;
+ (void) sscop_send_bgn(sop, SSCOP_SOURCE_USER);
+
+ /*
+ * Restart retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc;
+
+ } else {
+
+ /*
+ * Retransmit limit exceeded, terminate session
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper,
+ sop->so_toku, sop->so_connvc,
+ SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
+ if (err) {
+ /*
+ * Error, force retry
+ */
+ sop->so_timer[SSCOP_T_CC] = 1;
+ break;
+ }
+
+ /*
+ * Notify peer of termination
+ */
+ (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
+
+ /*
+ * Report establishment failure
+ */
+ sscop_maa_error(sop, 'O');
+
+ /*
+ * Clear reestablishment flag
+ */
+ sop->so_flags &= ~SOF_REESTAB;
+
+ /*
+ * Return to IDLE state
+ */
+ sop->so_state = SOS_IDLE;
+ }
+ break;
+
+ case SOS_OUTDISC:
+ /*
+ * No response to our END yet
+ */
+ if (sop->so_connctl < sop->so_parm.sp_maxcc) {
+
+ /*
+ * Send another END PDU
+ */
+ sop->so_connctl++;
+ (void) sscop_send_end(sop, SSCOP_SOURCE_LAST);
+
+ /*
+ * Restart retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc;
+
+ } else {
+
+ /*
+ * Retransmit limit exceeded, force session termination
+ */
+ STACK_CALL(SSCOP_RELEASE_CNF, sop->so_upper,
+ sop->so_toku, sop->so_connvc, 0, 0, err);
+ if (err) {
+ /*
+ * Error, force retry
+ */
+ sop->so_timer[SSCOP_T_CC] = 1;
+ break;
+ }
+
+ /*
+ * Report establishment failure
+ */
+ sscop_maa_error(sop, 'O');
+
+ /*
+ * Return to IDLE state
+ */
+ sop->so_state = SOS_IDLE;
+ }
+ break;
+
+ case SOS_OUTRESYN:
+rexmitrs:
+ /*
+ * No response to our RS yet
+ */
+ if (sop->so_connctl < sop->so_parm.sp_maxcc) {
+
+ /*
+ * Send another RS PDU
+ */
+ sop->so_connctl++;
+ (void) sscop_send_rs(sop);
+
+ /*
+ * Restart retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc;
+
+ } else {
+
+ /*
+ * Retransmit limit exceeded, terminate session
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper,
+ sop->so_toku, sop->so_connvc,
+ SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
+ if (err) {
+ /*
+ * Error, force retry
+ */
+ sop->so_timer[SSCOP_T_CC] = 1;
+ break;
+ }
+
+ /*
+ * Notify peer of termination
+ */
+ (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
+
+ /*
+ * Report establishment failure
+ */
+ sscop_maa_error(sop, 'O');
+
+ if (sop->so_vers == SSCOP_VERS_QSAAL)
+ /*
+ * Clear connection data
+ */
+ qsaal1_clear_connection(sop);
+
+ /*
+ * Return to IDLE state
+ */
+ sop->so_state = SOS_IDLE;
+ }
+ break;
+
+ case SOS_CONRESYN: /* Q.SAAL1 */
+#if (SOS_OUTRECOV != SOS_CONRESYN)
+ case SOS_OUTRECOV: /* Q.2110 */
+#endif
+ if (sop->so_vers == SSCOP_VERS_QSAAL) {
+ /*
+ * Handle timeout for SOS_CONRESYN
+ */
+ goto rexmitrs;
+ }
+
+ /*
+ * Handle timeout for SOS_OUTRECOV
+ */
+
+ /*
+ * No response to our ER yet
+ */
+ if (sop->so_connctl < sop->so_parm.sp_maxcc) {
+
+ /*
+ * Send another ER PDU
+ */
+ sop->so_connctl++;
+ (void) sscop_send_er(sop);
+
+ /*
+ * Restart retransmit timer
+ */
+ sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc;
+
+ } else {
+
+ /*
+ * Retransmit limit exceeded, terminate session
+ */
+ STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper,
+ sop->so_toku, sop->so_connvc,
+ SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
+ if (err) {
+ /*
+ * Error, force retry
+ */
+ sop->so_timer[SSCOP_T_CC] = 1;
+ break;
+ }
+
+ /*
+ * Notify peer of termination
+ */
+ (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
+
+ /*
+ * Report establishment failure
+ */
+ sscop_maa_error(sop, 'O');
+
+ /*
+ * Clear receiver buffer
+ */
+ sscop_rcvr_drain(sop);
+
+ /*
+ * Return to IDLE state
+ */
+ sop->so_state = SOS_IDLE;
+ }
+ break;
+
+ default:
+ log(LOG_ERR, "sscop: invalid %s state: sop=0x%x, state=%d\n",
+ "Timer_CC", (int)sop, sop->so_state);
+ }
+}
+
diff --git a/sys/netatm/uni/sscop_upper.c b/sys/netatm/uni/sscop_upper.c
new file mode 100644
index 0000000..be9556d
--- /dev/null
+++ b/sys/netatm/uni/sscop_upper.c
@@ -0,0 +1,412 @@
+/*
+ *
+ * ===================================
+ * 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: sscop_upper.c,v 1.6 1998/08/26 23:29:20 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * SSCOP - CPCS SAP interface processing
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: sscop_upper.c,v 1.6 1998/08/26 23:29:20 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/uni.h>
+#include <netatm/uni/sscop.h>
+#include <netatm/uni/sscop_misc.h>
+#include <netatm/uni/sscop_pdu.h>
+#include <netatm/uni/sscop_var.h>
+
+
+/*
+ * Local functions
+ */
+static caddr_t sscop_pdu_receive __P((KBuffer *, struct sscop *, int *));
+
+
+/*
+ * Local variables
+ */
+static union {
+ struct bgn_pdu t_bgn;
+ struct bgak_pdu t_bgak;
+ struct end_pdu t_end;
+ struct endak_q2110_pdu t_endak_q2110;
+ struct endak_qsaal_pdu t_endak_qsaal;
+ struct rs_pdu t_rs;
+ struct rsak_q2110_pdu t_rsak_q2110;
+ struct rsak_qsaal_pdu t_rsak_qsaal;
+ struct bgrej_pdu t_bgrej;
+ struct sd_pdu t_sd;
+ struct sdp_pdu t_sdp;
+ struct er_pdu t_er;
+ struct poll_pdu t_poll;
+ struct stat_pdu t_stat;
+ struct ustat_pdu t_ustat;
+ struct ud_pdu t_ud;
+ struct md_pdu t_md;
+ struct erak_pdu t_erak;
+} sscop_trailer;
+
+
+/*
+ * PDU length validation table
+ */
+struct pdulen {
+ int min;
+ int max;
+};
+
+static struct pdulen qsaal_pdulen[] = {
+ {0, 0},
+ {sizeof(struct bgn_pdu), sizeof(struct bgn_pdu)},
+ {sizeof(struct bgak_pdu), sizeof(struct bgak_pdu)},
+ {sizeof(struct end_pdu), sizeof(struct end_pdu)},
+ {sizeof(struct endak_qsaal_pdu),sizeof(struct endak_qsaal_pdu)},
+ {sizeof(struct rs_pdu), sizeof(struct rs_pdu)},
+ {sizeof(struct rsak_qsaal_pdu), sizeof(struct rsak_qsaal_pdu)},
+ {sizeof(struct bgrej_pdu), sizeof(struct bgrej_pdu)},
+ {sizeof(struct sd_pdu), sizeof(struct sd_pdu) + PDU_MAX_INFO},
+ {sizeof(struct sdp_pdu), sizeof(struct sdp_pdu) + PDU_MAX_INFO},
+ {sizeof(struct poll_pdu), sizeof(struct poll_pdu)},
+ {sizeof(struct stat_pdu), sizeof(struct stat_pdu) + PDU_MAX_STAT},
+ {sizeof(struct ustat_pdu), sizeof(struct ustat_pdu)},
+ {sizeof(struct ud_pdu), sizeof(struct ud_pdu) + PDU_MAX_INFO},
+ {sizeof(struct md_pdu), sizeof(struct md_pdu) + PDU_MAX_INFO},
+ {0, 0}
+};
+
+static struct pdulen q2110_pdulen[] = {
+ {0, 0},
+ {sizeof(struct bgn_pdu), sizeof(struct bgn_pdu) + PDU_MAX_UU},
+ {sizeof(struct bgak_pdu), sizeof(struct bgak_pdu) + PDU_MAX_UU},
+ {sizeof(struct end_pdu), sizeof(struct end_pdu) + PDU_MAX_UU},
+ {sizeof(struct endak_q2110_pdu),sizeof(struct endak_q2110_pdu)},
+ {sizeof(struct rs_pdu), sizeof(struct rs_pdu) + PDU_MAX_UU},
+ {sizeof(struct rsak_q2110_pdu), sizeof(struct rsak_q2110_pdu)},
+ {sizeof(struct bgrej_pdu), sizeof(struct bgrej_pdu) + PDU_MAX_UU},
+ {sizeof(struct sd_pdu), sizeof(struct sd_pdu) + PDU_MAX_INFO},
+ {sizeof(struct er_pdu), sizeof(struct er_pdu)},
+ {sizeof(struct poll_pdu), sizeof(struct poll_pdu)},
+ {sizeof(struct stat_pdu), sizeof(struct stat_pdu) + PDU_MAX_STAT},
+ {sizeof(struct ustat_pdu), sizeof(struct ustat_pdu)},
+ {sizeof(struct ud_pdu), sizeof(struct ud_pdu) + PDU_MAX_INFO},
+ {sizeof(struct md_pdu), sizeof(struct md_pdu) + PDU_MAX_INFO},
+ {sizeof(struct erak_pdu), sizeof(struct erak_pdu)}
+};
+
+
+/*
+ * PDUs with Pad Length Fields
+ */
+static u_char qsaal_padlen[] = {
+ 0, /* --- */
+ 0, /* BGN */
+ 0, /* BGAK */
+ 0, /* END */
+ 0, /* ENDAK */
+ 0, /* RS */
+ 0, /* RSAK */
+ 0, /* BGREJ */
+ 1, /* SD */
+ 1, /* SDP */
+ 0, /* POLL */
+ 0, /* STAT */
+ 0, /* USTAT */
+ 1, /* UD */
+ 1, /* MD */
+ 0 /* --- */
+};
+
+static u_char q2110_padlen[] = {
+ 0, /* --- */
+ 1, /* BGN */
+ 1, /* BGAK */
+ 1, /* END */
+ 0, /* ENDAK */
+ 1, /* RS */
+ 0, /* RSAK */
+ 1, /* BGREJ */
+ 1, /* SD */
+ 0, /* ER */
+ 0, /* POLL */
+ 0, /* STAT */
+ 0, /* USTAT */
+ 1, /* UD */
+ 1, /* MD */
+ 0 /* ERAK */
+};
+
+
+/*
+ * SSCOP Upper Stack Command Handler
+ *
+ * This function will receive all of the stack commands issued from the
+ * layer below SSCOP (ie. CPCS). Currently, only incoming PDUs will be
+ * received here. The appropriate processing function will be determined
+ * based on the received PDU type and the current sscop control block state.
+ *
+ * Arguments:
+ * cmd stack command code
+ * tok session token
+ * arg1 command specific argument
+ * arg2 command specific argument
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+sscop_upper(cmd, tok, arg1, arg2)
+ int cmd;
+ void *tok;
+ int arg1;
+ int arg2;
+{
+ struct sscop *sop = (struct sscop *)tok;
+ void (**ptab) __P((struct sscop *, KBuffer *, caddr_t));
+ void (*func) __P((struct sscop *, KBuffer *, caddr_t));
+ caddr_t trlr;
+ int type;
+
+ ATM_DEBUG5("sscop_upper: cmd=0x%x, sop=0x%x, state=%d, arg1=0x%x, arg2=0x%x\n",
+ cmd, (int)sop, sop->so_state, arg1, arg2);
+
+ switch (cmd) {
+
+ case CPCS_UNITDATA_SIG:
+ /*
+ * Decode/validate received PDU
+ */
+ trlr = sscop_pdu_receive((KBuffer *)arg1, sop, &type);
+ if (trlr == NULL) {
+ return;
+ }
+
+ /*
+ * Validate sscop state
+ */
+ if (sop->so_state > SOS_MAXSTATE) {
+ log(LOG_ERR,
+ "sscop_upper: invalid state sop=0x%x, state=%d\n",
+ (int)sop, sop->so_state);
+ KB_FREEALL((KBuffer *)arg1);
+ return;
+ }
+
+ /*
+ * Call event processing function
+ */
+ ptab = sop->so_vers == SSCOP_VERS_QSAAL ?
+ sscop_qsaal_pdutab[type]:
+ sscop_q2110_pdutab[type];
+ func = ptab[sop->so_state];
+ if (func == NULL) {
+ log(LOG_ERR,
+ "sscop_upper: unsupported pdu=%d, state=%d\n",
+ type, sop->so_state);
+ break;
+ }
+ (*func)(sop, (KBuffer *)arg1, trlr);
+ break;
+
+ default:
+ log(LOG_ERR, "sscop_upper: unknown cmd 0x%x, sop=0x%x\n",
+ cmd, (int)sop);
+ }
+
+ return;
+}
+
+
+/*
+ * Decode and Validate Received PDU
+ *
+ * This function will process all received SSCOP PDUs. The PDU type will be
+ * determined and PDU format validation will be performed. If the PDU is
+ * successfully decoded and validated, the buffer chain will have the PDU
+ * trailer removed, but any resultant zero-length buffers will NOT be freed.
+ * If the PDU fails validation, then the buffer chain will be freed.
+ *
+ * Arguments:
+ * m pointer to PDU buffer chain
+ * sop pointer to sscop connection block
+ * typep address to store PDU type
+ *
+ * Returns:
+ * addr pointer to (contiguous) PDU trailer
+ * 0 invalid PDU, buffer chain freed
+ *
+ */
+static caddr_t
+sscop_pdu_receive(m, sop, typep)
+ KBuffer *m;
+ struct sscop *sop;
+ int *typep;
+{
+ KBuffer *m0, *ml, *mn;
+ caddr_t cp, tp;
+ int len, tlen, type, plen;
+
+ /*
+ * Calculate PDU length and find the last two buffers in the chain
+ */
+ len = 0;
+ for (m0 = m, ml = mn = NULL; m0; m0 = KB_NEXT(m0)) {
+ len += KB_LEN(m0);
+ mn = ml;
+ ml = m0;
+ }
+
+ /*
+ * Make sure we've got a minimum sized PDU
+ */
+ if (len < PDU_MIN_LEN)
+ goto badpdu;
+
+ /*
+ * Get PDU type field
+ */
+ if (KB_LEN(ml) >= PDU_MIN_LEN) {
+ KB_DATAEND(ml, tp, caddr_t);
+ tp -= PDU_MIN_LEN;
+ } else {
+ KB_DATAEND(mn, tp, caddr_t);
+ tp -= (PDU_MIN_LEN - KB_LEN(ml));
+ }
+ *typep = type = *tp & PT_TYPE_MASK;
+
+ /*
+ * Check up on PDU length
+ */
+ if (sop->so_vers == SSCOP_VERS_QSAAL) {
+ if ((len < (tlen = qsaal_pdulen[type].min)) ||
+ (len > qsaal_pdulen[type].max) ||
+ (len & PDU_LEN_MASK))
+ goto badpdu;
+ } else {
+ if ((len < (tlen = q2110_pdulen[type].min)) ||
+ (len > q2110_pdulen[type].max) ||
+ (len & PDU_LEN_MASK))
+ goto badpdu;
+ }
+
+ /*
+ * Get a contiguous, aligned PDU trailer and adjust buffer
+ * controls to remove trailer
+ */
+ if (KB_LEN(ml) >= tlen) {
+ /*
+ * Trailer is contained in last buffer
+ */
+ KB_TAILADJ(ml, -tlen);
+ KB_DATAEND(ml, cp, caddr_t);
+ if ((int)cp & PDU_ADDR_MASK) {
+ /*
+ * Trailer not aligned in buffer, use local memory
+ */
+ KM_COPY(cp, (caddr_t)&sscop_trailer, tlen);
+ cp = (caddr_t)&sscop_trailer;
+ }
+ } else {
+ /*
+ * Trailer is split across buffers, use local memory
+ */
+ caddr_t cp1;
+ int off = tlen - KB_LEN(ml);
+
+ cp = (caddr_t)&sscop_trailer;
+
+ /*
+ * Ensure trailer is within last two buffers
+ */
+ if ((mn == NULL) || (KB_LEN(mn) < off))
+ goto badpdu;
+
+ KB_DATASTART(ml, cp1, caddr_t);
+ KM_COPY(cp1, cp + off, KB_LEN(ml));
+ KB_LEN(ml) = 0;
+ KB_TAILADJ(mn, -off);
+ KB_DATAEND(mn, cp1, caddr_t);
+ KM_COPY(cp1, cp, off);
+ }
+
+ /*
+ * Get possible PDU Pad Length
+ */
+ if (sop->so_vers == SSCOP_VERS_QSAAL) {
+ if (qsaal_padlen[type])
+ plen = (*tp & PT_PAD_MASK) >> PT_PAD_SHIFT;
+ else
+ plen = 0;
+ } else {
+ if (q2110_padlen[type])
+ plen = (*tp & PT_PAD_MASK) >> PT_PAD_SHIFT;
+ else
+ plen = 0;
+ }
+
+ /*
+ * Perform Pad Length adjustments
+ */
+ if (plen) {
+ if (KB_LEN(ml) >= plen) {
+ /*
+ * All pad bytes in last buffer
+ */
+ KB_TAILADJ(ml, -plen);
+ } else {
+ /*
+ * Pad bytes split between buffers
+ */
+ plen -= KB_LEN(ml);
+ if ((mn == NULL) || (KB_LEN(mn) < plen))
+ goto badpdu;
+ KB_LEN(ml) = 0;
+ KB_TAILADJ(mn, -plen);
+ }
+ }
+
+ return (cp);
+
+badpdu:
+ /*
+ * This MAA Error is only supposed to be for a PDU length violation,
+ * but we use it for any PDU format error.
+ */
+ sscop_maa_error(sop, 'U');
+ sscop_pdu_print(sop, m, "badpdu received");
+ KB_FREEALL(m);
+ return (NULL);
+}
+
diff --git a/sys/netatm/uni/sscop_var.h b/sys/netatm/uni/sscop_var.h
new file mode 100644
index 0000000..9a739d3
--- /dev/null
+++ b/sys/netatm/uni/sscop_var.h
@@ -0,0 +1,283 @@
+/*
+ *
+ * ===================================
+ * 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: sscop_var.h,v 1.6 1998/04/07 23:21:57 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * SSCOP protocol control blocks
+ *
+ */
+
+#ifndef _UNI_SSCOP_VAR_H
+#define _UNI_SSCOP_VAR_H
+
+/*
+ * Structure containing information for each SSCOP connection.
+ */
+struct sscop {
+ struct sscop *so_next; /* Next connection in chain */
+ u_char so_state; /* Connection state (see below) */
+ u_short so_flags; /* Connection flags (see below) */
+ enum sscop_vers so_vers; /* SSCOP version */
+
+ /* Transmitter variables */
+ sscop_seq so_send; /* VT(S) - next SD to send */
+ sscop_seq so_sendmax; /* VT(MS) - max SD to send + 1 */
+ sscop_seq so_ack; /* VT(A) - next expected ack */
+ sscop_seq so_pollsend; /* VT(PS) - last POLL sent */
+ sscop_seq so_pollack; /* VT(PA) - next expected STAT */
+ short so_polldata; /* VT(PD) - SD's sent between POLLs */
+ short so_connctl; /* VT(CC) - un-ack'd BGN,END,ER,RS */
+ u_char so_sendconn; /* VT(SQ) - last BGN,ER,RS sent */
+
+ /* Receiver variables */
+ sscop_seq so_rcvnext; /* VR(R) - next SD to receive */
+ sscop_seq so_rcvhigh; /* VR(H) - next highest SD to receive */
+ sscop_seq so_rcvmax; /* VR(MR) - max SD to receive + 1 */
+ u_char so_rcvconn; /* VR(SQ) - last BGN,ER,RS received */
+
+ /* PDU queues */
+ KBuffer *so_xmit_hd; /* SD transmission queue head */
+ KBuffer *so_xmit_tl; /* SD transmission queue tail */
+ struct pdu_hdr *so_rexmit_hd; /* SD retransmission queue head */
+ struct pdu_hdr *so_rexmit_tl; /* SD retransmission queue head */
+ struct pdu_hdr *so_pack_hd; /* SD pending ack queue head */
+ struct pdu_hdr *so_pack_tl; /* SD pending ack queue tail */
+ struct pdu_hdr *so_recv_hd; /* SD receive queue head */
+ struct pdu_hdr *so_recv_tl; /* SD receive queue tail */
+
+ /* Connection parameters */
+ struct sscop_parms so_parm; /* Connection parameters */
+
+ /* Timers */
+ u_short so_timer[SSCOP_T_NUM]; /* Connection timers */
+
+ /* Stack variables */
+ Atm_connvc *so_connvc; /* Connection vcc for this stack */
+ void *so_toku; /* Stack upper layer's token */
+ void *so_tokl; /* Stack lower layer's token */
+ void (*so_upper) /* Stack upper layer's interface */
+ __P((int, void *, int, int));
+ void (*so_lower) /* Stack lower layer's interface */
+ __P((int, void *, int, int));
+ u_short so_headout; /* Output buffer headroom */
+};
+
+/*
+ * Connection States
+ *
+ * Notes:
+ * # - state valid only for Q.SAAL1
+ * ## - state valid only for Q.2110
+ */
+#define SOS_INST 0 /* Instantiated, waiting for INIT */
+#define SOS_IDLE 1 /* Idle connection */
+#define SOS_OUTCONN 2 /* Outgoing connection pending */
+#define SOS_INCONN 3 /* Incoming connection pending */
+#define SOS_OUTDISC 4 /* Outgoing disconnection pending */
+#define SOS_OUTRESYN 5 /* Outgoing resynchronization pending */
+#define SOS_INRESYN 6 /* Incoming resynchronization pending */
+#define SOS_CONRESYN 7 /* Concurrent resynch pending (#) */
+#define SOS_OUTRECOV 7 /* Outgoing recovery pending (##) */
+#define SOS_RECOVRSP 8 /* Recovery response pending (##) */
+#define SOS_INRECOV 9 /* Incoming recovery pending (##) */
+#define SOS_READY 10 /* Data transfer ready */
+#define SOS_TERM 11 /* Waiting for TERM */
+
+#define SOS_MAXSTATE 11 /* Maximum state value */
+#define SOS_NUMSTATES (SOS_MAXSTATE+1)/* Number of states */
+
+/*
+ * Connection Flags
+ */
+#define SOF_NOCLRBUF 0x0001 /* Clear buffers = no */
+#define SOF_REESTAB 0x0002 /* SSCOP initiated reestablishment */
+#define SOF_XMITSRVC 0x0004 /* Transmit queues need servicing */
+#define SOF_KEEPALIVE 0x0008 /* Polling in transient phase */
+#define SOF_ENDSSCOP 0x0010 /* Last END PDU, SOURCE=SSCOP */
+#define SOF_NOCREDIT 0x0020 /* Transmit window closed */
+
+
+/*
+ * SSCOP statistics
+ */
+struct sscop_stat {
+ u_long sos_connects; /* Connection instances */
+ u_long sos_aborts; /* Connection aborts */
+ u_long sos_maa_error[MAA_ERROR_COUNT]; /* Management errors */
+};
+
+#ifdef ATM_KERNEL
+/*
+ * Global function declarations
+ */
+ /* sscop.c */
+int sscop_start __P((void));
+int sscop_stop __P((void));
+void sscop_maa_error __P((struct sscop *, int));
+void sscop_abort __P((struct sscop *, char *));
+
+ /* sscop_lower.c */
+void sscop_lower __P((int, void *, int, int));
+void sscop_aa_noop_0 __P((struct sscop *, int, int));
+void sscop_aa_noop_1 __P((struct sscop *, int, int));
+void sscop_init_inst __P((struct sscop *, int, int));
+void sscop_term_all __P((struct sscop *, int, int));
+
+ /* sscop_pdu.c */
+int sscop_send_bgn __P((struct sscop *, int));
+int sscop_send_bgak __P((struct sscop *));
+int sscop_send_bgrej __P((struct sscop *));
+int sscop_send_end __P((struct sscop *, int));
+int sscop_send_endak __P((struct sscop *));
+int sscop_send_rs __P((struct sscop *));
+int sscop_send_rsak __P((struct sscop *));
+int sscop_send_er __P((struct sscop *));
+int sscop_send_erak __P((struct sscop *));
+int sscop_send_poll __P((struct sscop *));
+int sscop_send_stat __P((struct sscop *, sscop_seq));
+int sscop_send_ustat __P((struct sscop *, sscop_seq));
+int sscop_send_ud __P((struct sscop *, KBuffer *));
+void sscop_pdu_print __P((struct sscop *, KBuffer *, char *));
+
+ /* sscop_sigaa.c */
+void sscop_estreq_idle __P((struct sscop *, int, int));
+void sscop_estrsp_inconn __P((struct sscop *, int, int));
+void sscop_relreq_outconn __P((struct sscop *, int, int));
+void sscop_relreq_inconn __P((struct sscop *, int, int));
+void sscop_relreq_ready __P((struct sscop *, int, int));
+void sscop_datreq_ready __P((struct sscop *, int, int));
+void sscop_udtreq_all __P((struct sscop *, int, int));
+
+ /* sscop_sigcpcs.c */
+void sscop_noop __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_bgn_idle __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_bgn_outdisc __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_bgn_outresyn __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_bgn_inresyn __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_bgak_error __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_bgak_idle __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_bgak_outconn __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_bgrej_error __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_bgrej_outconn __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_bgrej_inconn __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_bgrej_outresyn __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_bgrej_ready __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_end_idle __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_end_inconn __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_end_outdisc __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_endak_error __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_endak_inconn __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_endak_outdisc __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_endak_ready __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_rs_error __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_rs_idle __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_rsak_error __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_rsak_idle __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_rsak_outresyn __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_sd_error __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_sd_idle __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_sd_inconn __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_poll_error __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_poll_idle __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_poll_inconn __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_stat_error __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_stat_idle __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_stat_inconn __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_stat_ready __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_ustat_error __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_ustat_idle __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_ustat_inconn __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_ustat_ready __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_ud_all __P((struct sscop *, KBuffer *, caddr_t));
+void sscop_md_all __P((struct sscop *, KBuffer *, caddr_t));
+
+ /* sscop_subr.c */
+KBuffer * sscop_stat_getelem __P((KBuffer *, sscop_seq *));
+struct pdu_hdr *sscop_pack_locate __P((struct sscop *, sscop_seq));
+void sscop_pack_free __P((struct sscop *, sscop_seq));
+void sscop_rexmit_insert __P((struct sscop *, struct pdu_hdr *));
+void sscop_rexmit_unlink __P((struct sscop *, struct pdu_hdr *));
+void sscop_xmit_drain __P((struct sscop *));
+int sscop_recv_insert __P((struct sscop *, struct pdu_hdr *));
+void sscop_rcvr_drain __P((struct sscop *));
+void sscop_service_xmit __P((struct sscop *));
+int sscop_is_rexmit __P((struct sscop *, u_char));
+void sscop_set_poll __P((struct sscop *));
+
+ /* sscop_timer.c */
+void sscop_timeout __P((struct atm_time *));
+
+ /* sscop_upper.c */
+void sscop_upper __P((int, void *, int, int));
+
+ /* q2110_sigaa.c */
+
+ /* q2110_sigcpcs.c */
+
+ /* q2110_subr.c */
+void q2110_clear_xmit __P((struct sscop *));
+void q2110_init_state __P((struct sscop *));
+void q2110_prep_retrieve __P((struct sscop *));
+void q2110_prep_recovery __P((struct sscop *));
+void q2110_deliver_data __P((struct sscop *));
+void q2110_error_recovery __P((struct sscop *));
+
+ /* qsaal1_sigaa.c */
+
+ /* qsaal1_sigcpcs.c */
+
+ /* qsaal1_subr.c */
+void qsaal1_reestablish __P((struct sscop *));
+void qsaal1_reset_xmit __P((struct sscop *));
+void qsaal1_reset_rcvr __P((struct sscop *));
+void qsaal1_clear_connection __P((struct sscop *));
+
+
+/*
+ * External variables
+ */
+extern struct sp_info sscop_pool;
+extern int sscop_vccnt;
+extern struct sscop *sscop_head;
+extern struct sscop_stat sscop_stat;
+extern struct atm_time sscop_timer;
+extern void (*(*sscop_qsaal_aatab[]))
+ __P((struct sscop *, int, int));
+extern void (*(*sscop_q2110_aatab[]))
+ __P((struct sscop *, int, int));
+extern void (*(*sscop_qsaal_pdutab[]))
+ __P((struct sscop *, KBuffer *, caddr_t));
+extern void (*(*sscop_q2110_pdutab[]))
+ __P((struct sscop *, KBuffer *, caddr_t));
+
+#endif /* ATM_KERNEL */
+
+#endif /* _UNI_SSCOP_VAR_H */
diff --git a/sys/netatm/uni/uni.h b/sys/netatm/uni/uni.h
new file mode 100644
index 0000000..700e859
--- /dev/null
+++ b/sys/netatm/uni/uni.h
@@ -0,0 +1,50 @@
+/*
+ *
+ * ===================================
+ * 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: uni.h,v 1.2 1997/05/06 22:20:39 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * Protocol definitions
+ *
+ */
+
+#ifndef _UNI_UNI_H
+#define _UNI_UNI_H
+
+/*
+ * UNI Version
+ */
+enum uni_vers {
+ UNI_VERS_3_0,
+ UNI_VERS_3_1,
+ UNI_VERS_4_0
+};
+
+#endif /* _UNI_UNI_H */
diff --git a/sys/netatm/uni/uni_load.c b/sys/netatm/uni/uni_load.c
new file mode 100644
index 0000000..23e7ff5
--- /dev/null
+++ b/sys/netatm/uni/uni_load.c
@@ -0,0 +1,450 @@
+/*
+ *
+ * ===================================
+ * 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: uni_load.c,v 1.6 1997/05/06 22:20:43 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * Loadable kernel module support
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: uni_load.c,v 1.6 1997/05/06 22:20:43 mks Exp $";
+#endif
+
+#ifndef ATM_UNI_MODULE
+#include "opt_atm.h"
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/uni.h>
+
+/*
+ * External functions
+ */
+int sscop_start __P((void));
+int sscop_stop __P((void));
+int sscf_uni_start __P((void));
+int sscf_uni_stop __P((void));
+int uniip_start __P((void));
+int uniip_stop __P((void));
+int unisig_start __P((void));
+int unisig_stop __P((void));
+
+/*
+ * Local functions
+ */
+static int uni_start __P((void));
+static int uni_stop __P((void));
+
+
+/*
+ * Initialize uni processing
+ *
+ * This will be called during module loading. We just notify all of our
+ * sub-services to initialize.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 startup was successful
+ * errno startup failed - reason indicated
+ *
+ */
+static int
+uni_start()
+{
+ int err;
+
+ /*
+ * Verify software version
+ */
+ if (atm_version != ATM_VERSION) {
+ log(LOG_ERR, "version mismatch: uni=%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);
+ }
+
+ /*
+ * Initialize uni sub-services
+ */
+ err = sscop_start();
+ if (err)
+ goto done;
+
+ err = sscf_uni_start();
+ if (err)
+ goto done;
+
+ err = unisig_start();
+ if (err)
+ goto done;
+
+ err = uniip_start();
+ if (err)
+ goto done;
+
+done:
+ return (err);
+}
+
+
+/*
+ * Halt uni processing
+ *
+ * This will be called just prior to unloading the module from
+ * memory. All sub-services will be notified of the termination.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 shutdown was successful
+ * errno shutdown failed - reason indicated
+ *
+ */
+static int
+uni_stop()
+{
+ int err, s = splnet();
+
+ /*
+ * Terminate uni sub-services
+ */
+ err = uniip_stop();
+ if (err)
+ goto done;
+
+ err = unisig_stop();
+ if (err)
+ goto done;
+
+ err = sscf_uni_stop();
+ if (err)
+ goto done;
+
+ err = sscop_stop();
+ if (err)
+ goto done;
+
+done:
+ (void) splx(s);
+ return (err);
+}
+
+
+#ifdef ATM_UNI_MODULE
+/*
+ *******************************************************************
+ *
+ * Loadable Module Support
+ *
+ *******************************************************************
+ */
+static int uni_doload __P((void));
+static int uni_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
+uni_doload()
+{
+ int err = 0;
+
+ /*
+ * Start us up
+ */
+ err = uni_start();
+ if (err)
+ /* Problems, clean up */
+ (void)uni_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
+uni_dounload()
+{
+ int err = 0;
+
+ /*
+ * OK, try to clean up our mess
+ */
+ err = uni_stop();
+
+ return (err);
+}
+
+
+#ifdef sun
+/*
+ * Loadable driver description
+ */
+struct vdldrv uni_drv = {
+ VDMAGIC_PSEUDO, /* Pseudo Driver */
+ "uni_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
+uni_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 = uni_doload();
+ if (err == 0)
+ /* Let vd driver know about us */
+ vdp->vdd_vdtab = (struct vdlinkage *)&uni_drv;
+ break;
+
+ case VDUNLOAD:
+ /*
+ * Module Unload
+ */
+ err = uni_dounload();
+ break;
+
+ case VDSTAT:
+ /*
+ * Module Status
+ */
+
+ /* Not much to say at the moment */
+
+ break;
+
+ default:
+ log(LOG_ERR, "uni_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(uni);
+
+
+/*
+ * 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
+uni_load(lkmtp, cmd)
+ struct lkm_table *lkmtp;
+ int cmd;
+{
+ return(uni_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
+uni_unload(lkmtp, cmd)
+ struct lkm_table *lkmtp;
+ int cmd;
+{
+ return(uni_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
+uni_mod(lkmtp, cmd, ver)
+ struct lkm_table *lkmtp;
+ int cmd;
+ int ver;
+{
+ MOD_DISPATCH(uni, lkmtp, cmd, ver,
+ uni_load, uni_unload, lkm_nullcmd);
+}
+#endif /* __FreeBSD__ */
+
+#else /* !ATM_UNI_MODULE */
+
+/*
+ *******************************************************************
+ *
+ * Kernel Compiled Module Support
+ *
+ *******************************************************************
+ */
+static void uni_doload __P((void *));
+
+SYSINIT(atmuni, SI_SUB_PROTO_END, SI_ORDER_ANY, uni_doload, NULL)
+
+/*
+ * Kernel initialization
+ *
+ * Arguments:
+ * arg Not used
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+uni_doload(void *arg)
+{
+ int err = 0;
+
+ /*
+ * Start us up
+ */
+ err = uni_start();
+ if (err) {
+ /* Problems, clean up */
+ (void)uni_stop();
+
+ log(LOG_ERR, "ATM UNI unable to initialize (%d)!!\n", err);
+ }
+ return;
+}
+#endif /* ATM_UNI_MODULE */
+
diff --git a/sys/netatm/uni/uniarp.c b/sys/netatm/uni/uniarp.c
new file mode 100644
index 0000000..f316a73
--- /dev/null
+++ b/sys/netatm/uni/uniarp.c
@@ -0,0 +1,1231 @@
+/*
+ *
+ * ===================================
+ * 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: uniarp.c,v 1.10 1998/07/20 18:58:45 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * UNI ATMARP support (RFC1577)
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: uniarp.c,v 1.10 1998/07/20 18:58:45 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/ipatm/ipatm_var.h>
+#include <netatm/ipatm/ipatm_serv.h>
+#include <netatm/uni/unisig_var.h>
+#include <netatm/uni/uniip_var.h>
+
+
+/*
+ * Global variables
+ */
+struct uniarp *uniarp_arptab[UNIARP_HASHSIZ] = {NULL};
+struct uniarp *uniarp_nomaptab = NULL;
+struct uniarp *uniarp_pvctab = NULL;
+struct atm_time uniarp_timer = {0, 0}; /* Aging timer */
+struct uniarp_stat uniarp_stat = {0};
+int uniarp_print = 0;
+
+Atm_endpoint uniarp_endpt = {
+ NULL,
+ ENDPT_ATMARP,
+ uniarp_ioctl,
+ uniarp_getname,
+ uniarp_connected,
+ uniarp_cleared,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ uniarp_cpcs_data,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+struct sp_info uniarp_pool = {
+ "uni arp pool", /* si_name */
+ sizeof(struct uniarp), /* si_blksiz */
+ 10, /* si_blkcnt */
+ 200 /* si_maxallow */
+};
+
+
+/*
+ * Local variables
+ */
+static void uniarp_server_mode __P((struct uniip *));
+static void uniarp_client_mode __P((struct uniip *, Atm_addr *));
+
+
+/*
+ * Process module loading notification
+ *
+ * Called whenever the uni module is initializing.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 initialization successful
+ * errno initialization failed - reason indicated
+ *
+ */
+int
+uniarp_start()
+{
+ int err;
+
+ /*
+ * Register our endpoint
+ */
+ err = atm_endpoint_register(&uniarp_endpt);
+
+ return (err);
+}
+
+
+/*
+ * Process module unloading notification
+ *
+ * Called whenever the uni module is about to be unloaded. All signalling
+ * instances will have been previously detached. All uniarp resources
+ * must be freed now.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+uniarp_stop()
+{
+ int i;
+
+ /*
+ * Make sure the arp table is empty
+ */
+ for (i = 0; i < UNIARP_HASHSIZ; i++) {
+ if (uniarp_arptab[i] != NULL)
+ panic("uniarp_stop: arp table not empty");
+ }
+
+ /*
+ * Cancel timers
+ */
+ (void) atm_untimeout(&uniarp_timer);
+
+ /*
+ * De-register ourselves
+ */
+ (void) atm_endpoint_deregister(&uniarp_endpt);
+
+ /*
+ * Free our storage pools
+ */
+ atm_release_pool(&uniarp_pool);
+}
+
+
+/*
+ * Process IP Network Interface Activation
+ *
+ * Called whenever an IP network interface becomes active.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * uip pointer to UNI IP interface
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+uniarp_ipact(uip)
+ struct uniip *uip;
+{
+ struct unisig *usp;
+
+ ATM_DEBUG1("uniarp_ipact: uip=0x%x\n", (int)uip);
+
+ /*
+ * Set initial state
+ */
+ uip->uip_arpstate = UIAS_NOTCONF;
+ uip->uip_arpsvratm.address_format = T_ATM_ABSENT;
+ uip->uip_arpsvratm.address_length = 0;
+ uip->uip_arpsvrsub.address_format = T_ATM_ABSENT;
+ uip->uip_arpsvrsub.address_length = 0;
+
+ usp = (struct unisig *)uip->uip_ipnif->inf_nif->nif_pif->pif_siginst;
+ if (usp->us_addr.address_format != T_ATM_ABSENT)
+ uip->uip_flags |= UIF_IFADDR;
+
+ /*
+ * Make sure aging timer is running
+ */
+ if ((uniarp_timer.ti_flag & TIF_QUEUED) == 0)
+ atm_timeout(&uniarp_timer, UNIARP_AGING, uniarp_aging);
+
+ return;
+}
+
+
+/*
+ * Process IP Network Interface Deactivation
+ *
+ * Called whenever an IP network interface becomes inactive. All VCCs
+ * for this interface should already have been closed.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * uip pointer to UNI IP interface
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+uniarp_ipdact(uip)
+ struct uniip *uip;
+{
+ struct ip_nif *inp = uip->uip_ipnif;
+ struct uniarp *uap, *unext;
+ int i;
+
+ ATM_DEBUG1("uniarp_ipdact: uip=0x%x\n", (int)uip);
+
+ /*
+ * Delete all interface entries
+ */
+ for (i = 0; i < UNIARP_HASHSIZ; i++) {
+ for (uap = uniarp_arptab[i]; uap; uap = unext) {
+ unext = uap->ua_next;
+
+ if (uap->ua_intf != uip)
+ continue;
+
+ /*
+ * All VCCs should (better) be gone by now
+ */
+ if (uap->ua_ivp)
+ panic("uniarp_ipdact: entry not empty");
+
+ /*
+ * Clean up any loose ends
+ */
+ UNIARP_CANCEL(uap);
+
+ /*
+ * Delete entry from arp table and free entry
+ */
+ UNIARP_DELETE(uap);
+ atm_free((caddr_t)uap);
+ }
+ }
+
+ /*
+ * Clean up 'nomap' table
+ */
+ for (uap = uniarp_nomaptab; uap; uap = unext) {
+ unext = uap->ua_next;
+
+ if (uap->ua_intf != uip)
+ continue;
+
+ /*
+ * All VCCs should (better) be gone by now
+ */
+ if (uap->ua_ivp)
+ panic("uniarp_ipdact: entry not empty");
+
+ /*
+ * Clean up any loose ends
+ */
+ UNIARP_CANCEL(uap);
+
+ /*
+ * Delete entry from 'no map' table and free entry
+ */
+ UNLINK(uap, struct uniarp, uniarp_nomaptab, ua_next);
+ atm_free((caddr_t)uap);
+ }
+
+ /*
+ * Also clean up pvc table
+ */
+ for (uap = uniarp_pvctab; uap; uap = unext) {
+ unext = uap->ua_next;
+
+ if (uap->ua_intf != uip)
+ continue;
+
+ /*
+ * All PVCs should (better) be gone by now
+ */
+ panic("uniarp_ipdact: pvc table not empty");
+ }
+
+ /*
+ * Cancel arp interface timer
+ */
+ UNIIP_ARP_CANCEL(uip);
+
+ /*
+ * Stop aging timer if this is the last active interface
+ */
+ if (uniip_head == uip && uip->uip_next == NULL)
+ (void) atm_untimeout(&uniarp_timer);
+}
+
+
+/*
+ * Process Interface ATM Address Change
+ *
+ * This function is called whenever the ATM address for a physical
+ * interface is set/changed.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * sip pointer to interface's UNI signalling instance
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+uniarp_ifaddr(sip)
+ struct siginst *sip;
+{
+ struct atm_nif *nip;
+ struct uniip *uip;
+
+ ATM_DEBUG1("uniarp_ifaddr: sip=0x%x\n", (int)sip);
+
+ /*
+ * We've got to handle this for every network interface
+ */
+ for (nip = sip->si_pif->pif_nif; nip; nip = nip->nif_pnext) {
+
+ /*
+ * Find our control blocks
+ */
+ for (uip = uniip_head; uip; uip = uip->uip_next) {
+ if (uip->uip_ipnif->inf_nif == nip)
+ break;
+ }
+ if (uip == NULL)
+ continue;
+
+ /*
+ * We don't support changing prefix (yet)
+ */
+ if (uip->uip_flags & UIF_IFADDR) {
+ log(LOG_ERR, "uniarp_ifaddr: change not supported\n");
+ continue;
+ }
+
+ /*
+ * Note that address has been set and figure out what
+ * to do next
+ */
+ uip->uip_flags |= UIF_IFADDR;
+
+ if (uip->uip_arpstate == UIAS_CLIENT_PADDR) {
+ /*
+ * This is what we're waiting for
+ */
+ uniarp_client_mode(uip, NULL);
+ }
+ }
+
+ return;
+}
+
+
+/*
+ * Set ATMARP Server Mode
+ *
+ * This function is called to configure the local node to become the
+ * ATMARP server for the specified LIS.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * uip pointer to UNI IP interface
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+uniarp_server_mode(uip)
+ struct uniip *uip;
+{
+ struct ip_nif *inp;
+ struct atm_nif *nip;
+ struct siginst *sgp;
+ struct ipvcc *ivp, *inext;
+ struct uniarp *uap, *unext;
+ int i;
+
+ ATM_DEBUG1("uniarp_server_mode: uip=0x%x\n", (int)uip);
+
+ /*
+ * Handle client/server mode changes first
+ */
+ switch (uip->uip_arpstate) {
+
+ case UIAS_NOTCONF:
+ case UIAS_SERVER_ACTIVE:
+ case UIAS_CLIENT_PADDR:
+ /*
+ * Nothing to undo
+ */
+ break;
+
+ case UIAS_CLIENT_POPEN:
+ /*
+ * We're becoming the server, so kill the pending connection
+ */
+ UNIIP_ARP_CANCEL(uip);
+ if (ivp = uip->uip_arpsvrvcc) {
+ ivp->iv_flags &= ~IVF_NOIDLE;
+ uip->uip_arpsvrvcc = NULL;
+ (*ivp->iv_ipnif->inf_arpnotify)(ivp, MAP_FAILED);
+ }
+ break;
+
+ case UIAS_CLIENT_REGISTER:
+ case UIAS_CLIENT_ACTIVE:
+ /*
+ * We're becoming the server, but leave existing VCC as a
+ * "normal" IP VCC
+ */
+ UNIIP_ARP_CANCEL(uip);
+ ivp = uip->uip_arpsvrvcc;
+ ivp->iv_flags &= ~IVF_NOIDLE;
+ uip->uip_arpsvrvcc = NULL;
+ break;
+ }
+
+ /*
+ * Revalidate status for all arp entries on this interface
+ */
+ for (i = 0; i < UNIARP_HASHSIZ; i++) {
+ for (uap = uniarp_arptab[i]; uap; uap = unext) {
+ unext = uap->ua_next;
+
+ if (uap->ua_intf != uip)
+ continue;
+
+ if (uap->ua_origin >= UAO_PERM)
+ continue;
+
+ if (uap->ua_origin >= UAO_SCSP) {
+ if (uniarp_validate_ip(uip, &uap->ua_dstip,
+ uap->ua_origin) == 0)
+ continue;
+ }
+
+ if (uap->ua_ivp == NULL) {
+ UNIARP_CANCEL(uap);
+ UNIARP_DELETE(uap);
+ atm_free((caddr_t)uap);
+ continue;
+ }
+
+ if (uap->ua_flags & UAF_VALID) {
+ uap->ua_flags |= UAF_LOCKED;
+ for (ivp = uap->ua_ivp; ivp; ivp = inext) {
+ inext = ivp->iv_arpnext;
+ (*ivp->iv_ipnif->inf_arpnotify)
+ (ivp, MAP_INVALID);
+ }
+ uap->ua_flags &= ~(UAF_LOCKED | UAF_VALID);
+ }
+ uap->ua_aging = 1;
+ uap->ua_origin = 0;
+ }
+ }
+
+ /*
+ * OK, now let's make ourselves the server
+ */
+ inp = uip->uip_ipnif;
+ nip = inp->inf_nif;
+ sgp = nip->nif_pif->pif_siginst;
+ ATM_ADDR_SEL_COPY(&sgp->si_addr, nip->nif_sel, &uip->uip_arpsvratm);
+ uip->uip_arpsvrip = IA_SIN(inp->inf_addr)->sin_addr;
+ uip->uip_arpstate = UIAS_SERVER_ACTIVE;
+ return;
+}
+
+
+/*
+ * Set ATMARP Client Mode
+ *
+ * This function is called to configure the local node to be an ATMARP
+ * client on the specified LIS using the specified ATMARP server.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * uip pointer to UNI IP interface
+ * aap pointer to the ATMARP server's ATM address
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+uniarp_client_mode(uip, aap)
+ struct uniip *uip;
+ Atm_addr *aap;
+{
+ struct ip_nif *inp = uip->uip_ipnif;
+ struct uniarp *uap, *unext;
+ struct ipvcc *ivp, *inext;
+ int i;
+
+ ATM_DEBUG2("uniarp_client_mode: uip=0x%x, atm=(%s,-)\n",
+ (int)uip, aap ? unisig_addr_print(aap): "-");
+
+ /*
+ * Handle client/server mode changes first
+ */
+ switch (uip->uip_arpstate) {
+
+ case UIAS_NOTCONF:
+ case UIAS_CLIENT_PADDR:
+ /*
+ * Nothing to undo
+ */
+ break;
+
+ case UIAS_CLIENT_POPEN:
+ /*
+ * If this is this a timeout retry, just go do it
+ */
+ if (aap == NULL)
+ break;
+
+ /*
+ * If this isn't really a different arpserver, we're done
+ */
+ if (ATM_ADDR_EQUAL(aap, &uip->uip_arpsvratm))
+ return;
+
+ /*
+ * We're changing servers, so kill the pending connection
+ */
+ UNIIP_ARP_CANCEL(uip);
+ if (ivp = uip->uip_arpsvrvcc) {
+ ivp->iv_flags &= ~IVF_NOIDLE;
+ uip->uip_arpsvrvcc = NULL;
+ (*ivp->iv_ipnif->inf_arpnotify)(ivp, MAP_FAILED);
+ }
+ break;
+
+ case UIAS_CLIENT_REGISTER:
+ case UIAS_CLIENT_ACTIVE:
+ /*
+ * If this isn't really a different arpserver, we're done
+ */
+ if (ATM_ADDR_EQUAL(aap, &uip->uip_arpsvratm))
+ return;
+
+ /*
+ * We're changing servers, but leave existing VCC as a
+ * "normal" IP VCC
+ */
+ UNIIP_ARP_CANCEL(uip);
+ ivp = uip->uip_arpsvrvcc;
+ ivp->iv_flags &= ~IVF_NOIDLE;
+ uip->uip_arpsvrvcc = NULL;
+ break;
+
+ case UIAS_SERVER_ACTIVE:
+ /*
+ * We're changing from server mode, so...
+ *
+ * Reset valid/authoritative status for all arp entries
+ * on this interface
+ */
+ for (i = 0; i < UNIARP_HASHSIZ; i++) {
+ for (uap = uniarp_arptab[i]; uap; uap = unext) {
+ unext = uap->ua_next;
+
+ if (uap->ua_intf != uip)
+ continue;
+
+ if (uap->ua_origin >= UAO_PERM)
+ continue;
+
+ if (uap->ua_ivp == NULL) {
+ UNIARP_CANCEL(uap);
+ UNIARP_DELETE(uap);
+ atm_free((caddr_t)uap);
+ continue;
+ }
+
+ if (uap->ua_flags & UAF_VALID) {
+ uap->ua_flags |= UAF_LOCKED;
+ for (ivp = uap->ua_ivp; ivp;
+ ivp = inext) {
+ inext = ivp->iv_arpnext;
+ (*ivp->iv_ipnif->inf_arpnotify)
+ (ivp, MAP_INVALID);
+ }
+ uap->ua_flags &=
+ ~(UAF_LOCKED | UAF_VALID);
+ }
+ uap->ua_aging = 1;
+ uap->ua_origin = 0;
+ }
+ }
+ uip->uip_arpsvratm.address_format = T_ATM_ABSENT;
+ uip->uip_arpsvratm.address_length = 0;
+ uip->uip_arpsvrsub.address_format = T_ATM_ABSENT;
+ uip->uip_arpsvrsub.address_length = 0;
+ uip->uip_arpsvrip.s_addr = 0;
+ break;
+ }
+
+ /*
+ * Save the arp server address, if supplied now
+ */
+ if (aap)
+ ATM_ADDR_COPY(aap, &uip->uip_arpsvratm);
+
+ /*
+ * If the interface's ATM address isn't set yet, then we
+ * can't do much until it is
+ */
+ if ((uip->uip_flags & UIF_IFADDR) == 0) {
+ uip->uip_arpstate = UIAS_CLIENT_PADDR;
+ return;
+ }
+
+ /*
+ * Just to keep things simple, if we already have (or are trying to
+ * setup) any SVCs to our new server, kill the connections so we can
+ * open a "fresh" SVC for the arpserver connection.
+ */
+ for (i = 0; i < UNIARP_HASHSIZ; i++) {
+ for (uap = uniarp_arptab[i]; uap; uap = unext) {
+ unext = uap->ua_next;
+
+ if (ATM_ADDR_EQUAL(&uip->uip_arpsvratm,
+ &uap->ua_dstatm) &&
+ ATM_ADDR_EQUAL(&uip->uip_arpsvrsub,
+ &uap->ua_dstatmsub)) {
+ uap->ua_flags &= ~UAF_VALID;
+ for (ivp = uap->ua_ivp; ivp; ivp = inext) {
+ inext = ivp->iv_arpnext;
+ (*inp->inf_arpnotify)(ivp, MAP_FAILED);
+ }
+ }
+ }
+ }
+ for (uap = uniarp_nomaptab; uap; uap = unext) {
+ unext = uap->ua_next;
+
+ if (ATM_ADDR_EQUAL(&uip->uip_arpsvratm, &uap->ua_dstatm) &&
+ ATM_ADDR_EQUAL(&uip->uip_arpsvrsub, &uap->ua_dstatmsub)) {
+ uap->ua_flags &= ~UAF_VALID;
+ for (ivp = uap->ua_ivp; ivp; ivp = inext) {
+ inext = ivp->iv_arpnext;
+ (*inp->inf_arpnotify)(ivp, MAP_FAILED);
+ }
+ }
+ }
+
+ /*
+ * Now, get an arp entry for the server connection
+ */
+ uip->uip_arpstate = UIAS_CLIENT_POPEN;
+ uap = (struct uniarp *)atm_allocate(&uniarp_pool);
+ if (uap == NULL) {
+ UNIIP_ARP_TIMER(uip, 1 * ATM_HZ);
+ return;
+ }
+
+ /*
+ * Next, initiate an SVC to the server
+ */
+ if ((*inp->inf_createsvc)(&inp->inf_nif->nif_if, AF_ATM,
+ (caddr_t)&uip->uip_arpsvratm, &ivp)) {
+ atm_free((caddr_t)uap);
+ UNIIP_ARP_TIMER(uip, 1 * ATM_HZ);
+ return;
+ }
+
+ /*
+ * Finally, get everything set up and wait for the SVC
+ * connection to complete
+ */
+ uip->uip_arpsvrvcc = ivp;
+ ivp->iv_flags |= IVF_NOIDLE;
+
+ ATM_ADDR_COPY(&uip->uip_arpsvratm, &uap->ua_dstatm);
+ ATM_ADDR_COPY(&uip->uip_arpsvrsub, &uap->ua_dstatmsub);
+ uap->ua_intf = uip;
+
+ LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
+ ivp->iv_arpent = (struct arpmap *)uap;
+
+ LINK2TAIL(uap, struct uniarp, uniarp_nomaptab, ua_next);
+
+ return;
+}
+
+
+/*
+ * Process a UNI ARP interface timeout
+ *
+ * Called when a previously scheduled uniip arp interface timer expires.
+ * Processing will be based on the current uniip arp state.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * tip pointer to uniip arp timer control block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+uniarp_iftimeout(tip)
+ struct atm_time *tip;
+{
+ struct ip_nif *inp;
+ struct uniip *uip;
+
+
+ /*
+ * Back-off to uniip control block
+ */
+ uip = (struct uniip *)
+ ((caddr_t)tip - (int)(&((struct uniip *)0)->uip_arptime));
+
+ ATM_DEBUG2("uniarp_iftimeout: uip=0x%x, state=%d\n", (int)uip,
+ uip->uip_arpstate);
+
+ /*
+ * Process timeout based on protocol state
+ */
+ switch (uip->uip_arpstate) {
+
+ case UIAS_CLIENT_POPEN:
+ /*
+ * Retry opening arp server connection
+ */
+ uniarp_client_mode(uip, NULL);
+ break;
+
+ case UIAS_CLIENT_REGISTER:
+ /*
+ * Resend registration request
+ */
+ inp = uip->uip_ipnif;
+ (void) uniarp_arp_req(uip, &(IA_SIN(inp->inf_addr)->sin_addr));
+
+ /*
+ * Restart timer
+ */
+ UNIIP_ARP_TIMER(uip, 2 * ATM_HZ);
+
+ break;
+
+ case UIAS_CLIENT_ACTIVE:
+ /*
+ * Refresh our registration
+ */
+ inp = uip->uip_ipnif;
+ (void) uniarp_arp_req(uip, &(IA_SIN(inp->inf_addr)->sin_addr));
+
+ /*
+ * Restart timer
+ */
+ UNIIP_ARP_TIMER(uip, UNIARP_REGIS_RETRY);
+
+ break;
+
+ default:
+ log(LOG_ERR, "uniarp_iftimeout: invalid state %d\n",
+ uip->uip_arpstate);
+ }
+}
+
+
+/*
+ * UNI 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
+uniarp_ioctl(code, data, arg1)
+ int code;
+ caddr_t data;
+ caddr_t arg1;
+{
+ struct atmaddreq *aap;
+ struct atmdelreq *adp;
+ struct atmsetreq *asp;
+ struct atminfreq *aip;
+ struct air_arp_rsp aar;
+ struct air_asrv_rsp asr;
+ struct atm_pif *pip;
+ struct atm_nif *nip;
+ struct ipvcc *ivp, *inext;
+ struct uniip *uip;
+ struct uniarp *uap;
+ struct unisig *usp;
+ struct in_addr ip;
+ Atm_addr atmsub;
+ 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;
+ uip = (struct uniip *)arg1;
+ if (aap->aar_arp_addr.address_format != T_ATM_ENDSYS_ADDR) {
+ err = EINVAL;
+ break;
+ }
+ atmsub.address_format = T_ATM_ABSENT;
+ atmsub.address_length = 0;
+ ip = SATOSIN(&aap->aar_arp_dst)->sin_addr;
+
+ /*
+ * Validate IP address
+ */
+ if (uniarp_validate_ip(uip, &ip, aap->aar_arp_origin) != 0) {
+ err = EADDRNOTAVAIL;
+ break;
+ }
+
+ /*
+ * Add an entry to the cache
+ */
+ err = uniarp_cache_svc(uip, &ip, &aap->aar_arp_addr,
+ &atmsub, aap->aar_arp_origin);
+ break;
+
+ case AIOCS_DEL_ARP:
+ /*
+ * Delete an ARP mapping
+ */
+ adp = (struct atmdelreq *)data;
+ uip = (struct uniip *)arg1;
+ ip = SATOSIN(&adp->adr_arp_dst)->sin_addr;
+
+ /*
+ * Now find the entry to be deleted
+ */
+ UNIARP_LOOKUP(ip.s_addr, uap);
+ if (uap == NULL) {
+ err = ENOENT;
+ break;
+ }
+
+ /*
+ * Notify all VCCs using this entry that they must finish
+ * up now.
+ */
+ uap->ua_flags |= UAF_LOCKED;
+ for (ivp = uap->ua_ivp; ivp; ivp = inext) {
+ inext = ivp->iv_arpnext;
+ (*ivp->iv_ipnif->inf_arpnotify)(ivp, MAP_FAILED);
+ }
+
+ /*
+ * Now free up the entry
+ */
+ UNIARP_CANCEL(uap);
+ UNIARP_DELETE(uap);
+ atm_free((caddr_t)uap);
+ break;
+
+ case AIOCS_SET_ASV:
+ /*
+ * Set interface ARP server address
+ */
+ asp = (struct atmsetreq *)data;
+ for (uip = uniip_head; uip; uip = uip->uip_next) {
+ if (uip->uip_ipnif->inf_nif == (struct atm_nif *)arg1)
+ break;
+ }
+ if (uip == NULL) {
+ err = ENOPROTOOPT;
+ break;
+ }
+
+ /*
+ * Check for our own address
+ */
+ usp = (struct unisig *)
+ uip->uip_ipnif->inf_nif->nif_pif->pif_siginst;
+ if (ATM_ADDR_EQUAL(&asp->asr_arp_addr, &usp->us_addr)) {
+ asp->asr_arp_addr.address_format = T_ATM_ABSENT;
+ }
+
+ /*
+ * If we're going into server mode, make sure we can get
+ * the memory for the prefix list before continuing
+ */
+ if (asp->asr_arp_addr.address_format == T_ATM_ABSENT) {
+ i = asp->asr_arp_plen / sizeof(struct uniarp_prf);
+ if (i <= 0) {
+ err = EINVAL;
+ break;
+ }
+ buf_len = i * sizeof(struct uniarp_prf);
+ buf_addr = KM_ALLOC(buf_len, M_DEVBUF, M_NOWAIT);
+ if (buf_addr == NULL) {
+ err = ENOMEM;
+ break;
+ }
+ err = copyin(asp->asr_arp_pbuf, buf_addr, buf_len);
+ if (err) {
+ KM_FREE(buf_addr, buf_len, M_DEVBUF);
+ break;
+ }
+ } else {
+ /* Silence the compiler */
+ i = 0;
+ buf_addr = NULL;
+ }
+
+ /*
+ * Free any existing prefix address list
+ */
+ if (uip->uip_prefix != NULL) {
+ KM_FREE(uip->uip_prefix,
+ uip->uip_nprefix * sizeof(struct uniarp_prf),
+ M_DEVBUF);
+ uip->uip_prefix = NULL;
+ uip->uip_nprefix = 0;
+ }
+
+ if (asp->asr_arp_addr.address_format == T_ATM_ABSENT) {
+ /*
+ * Set ATMARP server mode
+ */
+ uip->uip_prefix = (struct uniarp_prf *)buf_addr;
+ uip->uip_nprefix = i;
+ uniarp_server_mode(uip);
+ } else
+ /*
+ * Set ATMARP client mode
+ */
+ uniarp_client_mode(uip, &asp->asr_arp_addr);
+ break;
+
+ case AIOCS_INF_ARP:
+ /*
+ * Get ARP table information
+ */
+ aip = (struct atminfreq *)data;
+
+ 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;
+
+ pip = ((struct siginst *)arg1)->si_pif;
+
+ /*
+ * Run through entire arp table
+ */
+ for (i = 0; i < UNIARP_HASHSIZ; i++) {
+ for (uap = uniarp_arptab[i]; uap; uap = uap->ua_next) {
+ /*
+ * We only want valid entries learned
+ * from the supplied interface.
+ */
+ nip = uap->ua_intf->uip_ipnif->inf_nif;
+ if (nip->nif_pif != pip)
+ continue;
+ if ((dst != INADDR_ANY) &&
+ (dst != uap->ua_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 =
+ uap->ua_dstip.s_addr;
+ (void) sprintf(aar.aap_intf, "%s%d",
+ nip->nif_if.if_name,
+ nip->nif_if.if_unit);
+ aar.aap_flags = uap->ua_flags;
+ aar.aap_origin = uap->ua_origin;
+ if (uap->ua_flags & UAF_VALID)
+ aar.aap_age = uap->ua_aging +
+ uap->ua_retry * UNIARP_RETRY_AGE;
+ else
+ aar.aap_age = 0;
+ ATM_ADDR_COPY(&uap->ua_dstatm, &aar.aap_addr);
+ ATM_ADDR_COPY(&uap->ua_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;
+ }
+
+ /*
+ * Now go through the 'nomap' table
+ */
+ if (err || (dst != INADDR_ANY))
+ goto updbuf;
+ for (uap = uniarp_nomaptab; uap; uap = uap->ua_next) {
+ /*
+ * We only want valid entries learned
+ * from the supplied interface.
+ */
+ nip = uap->ua_intf->uip_ipnif->inf_nif;
+ if (nip->nif_pif != pip)
+ 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 = 0;
+ (void) sprintf(aar.aap_intf, "%s%d",
+ nip->nif_if.if_name, nip->nif_if.if_unit);
+ aar.aap_flags = 0;
+ aar.aap_origin = uap->ua_origin;
+ aar.aap_age = 0;
+ ATM_ADDR_COPY(&uap->ua_dstatm, &aar.aap_addr);
+ ATM_ADDR_COPY(&uap->ua_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);
+ }
+
+updbuf:
+ /*
+ * Update the buffer pointer and length
+ */
+ aip->air_buf_addr = buf_addr;
+ aip->air_buf_len = buf_len;
+
+ /*
+ * If the user wants the refresh status reset and no
+ * errors have been encountered, then do the reset
+ */
+ if ((err == 0) && (aip->air_arp_flags & ARP_RESET_REF)) {
+ for (i = 0; i < UNIARP_HASHSIZ; i++) {
+ for (uap = uniarp_arptab[i]; uap;
+ uap = uap->ua_next) {
+ /*
+ * We only want valid entries learned
+ * from the supplied interface.
+ */
+ nip = uap->ua_intf->uip_ipnif->inf_nif;
+ if (nip->nif_pif != pip)
+ continue;
+ if ((dst != INADDR_ANY) &&
+ (dst != uap->ua_dstip.s_addr))
+ continue;
+
+ /*
+ * Reset refresh flag
+ */
+ uap->ua_flags &= ~UAF_REFRESH;
+ }
+ }
+ }
+ break;
+
+ case AIOCS_INF_ASV:
+ /*
+ * Get ARP server information
+ */
+ aip = (struct atminfreq *)data;
+
+ buf_addr = aip->air_buf_addr;
+ buf_len = aip->air_buf_len;
+
+ for (uip = uniip_head; uip; uip = uip->uip_next) {
+
+ if ((arg1 != NULL) &&
+ (uip->uip_ipnif->inf_nif != (struct atm_nif *)arg1))
+ continue;
+
+ /*
+ * Make sure there's room in the user's buffer
+ */
+ if (buf_len < sizeof(asr)) {
+ err = ENOSPC;
+ break;
+ }
+
+ /*
+ * Fill in info to be returned
+ */
+ nip = uip->uip_ipnif->inf_nif;
+ (void) sprintf(asr.asp_intf, "%s%d",
+ nip->nif_if.if_name, nip->nif_if.if_unit);
+ asr.asp_state = uip->uip_arpstate;
+ if (uip->uip_arpstate == UIAS_SERVER_ACTIVE) {
+ asr.asp_addr.address_format = T_ATM_ABSENT;
+ asr.asp_addr.address_length = 0;
+ } else {
+ ATM_ADDR_COPY(&uip->uip_arpsvratm,
+ &asr.asp_addr);
+ }
+ asr.asp_subaddr.address_format = T_ATM_ABSENT;
+ asr.asp_subaddr.address_length = 0;
+ asr.asp_nprefix = uip->uip_nprefix;
+
+ /*
+ * Copy the response into the user's buffer
+ */
+ if (err = copyout((caddr_t)&asr, buf_addr, sizeof(asr)))
+ break;
+ buf_addr += sizeof(asr);
+ buf_len -= sizeof(asr);
+
+ /*
+ * Copy the prefix list into the user's buffer
+ */
+ if (uip->uip_nprefix) {
+ i = uip->uip_nprefix
+ * sizeof(struct uniarp_prf);
+ if (buf_len < i) {
+ err = ENOSPC;
+ break;
+ }
+ if (err = copyout(uip->uip_prefix, buf_addr, i))
+ break;
+ buf_addr += i;
+ buf_len -= i;
+ }
+ }
+
+ /*
+ * Update the buffer pointer and length
+ */
+ aip->air_buf_addr = buf_addr;
+ aip->air_buf_len = buf_len;
+ break;
+
+ default:
+ err = EOPNOTSUPP;
+ }
+
+ return (err);
+}
+
+
+/*
+ * Get Connection's Application/Owner Name
+ *
+ * Arguments:
+ * tok uniarp connection token (pointer to ipvcc)
+ *
+ * Returns:
+ * addr pointer to string containing our name
+ *
+ */
+caddr_t
+uniarp_getname(tok)
+ void *tok;
+{
+ return ("ATMARP");
+}
+
diff --git a/sys/netatm/uni/uniarp_cache.c b/sys/netatm/uni/uniarp_cache.c
new file mode 100644
index 0000000..6c9537e
--- /dev/null
+++ b/sys/netatm/uni/uniarp_cache.c
@@ -0,0 +1,420 @@
+/*
+ *
+ * ===================================
+ * 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: uniarp_cache.c,v 1.8 1998/08/26 23:29:20 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * UNI ATMARP support (RFC1577) - ARP cache processing
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: uniarp_cache.c,v 1.8 1998/08/26 23:29:20 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/ipatm/ipatm_var.h>
+#include <netatm/ipatm/ipatm_serv.h>
+#include <netatm/uni/unisig_var.h>
+#include <netatm/uni/uniip_var.h>
+
+
+/*
+ * Add data to the arp table cache
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * uip pointer to UNI IP interface
+ * ip pointer to IP address structure
+ * atm pointer to ATM address structure
+ * atmsub pointer to ATM subaddress structure
+ * origin source of arp information
+ *
+ * Returns:
+ * 0 cache successfully updated
+ * else updated failed - reason indicated
+ *
+ */
+int
+uniarp_cache_svc(uip, ip, atm, atmsub, origin)
+ struct uniip *uip;
+ struct in_addr *ip;
+ Atm_addr *atm;
+ Atm_addr *atmsub;
+ u_int origin;
+{
+ struct ip_nif *inp;
+ struct ipvcc *ivp, *inext, *itail;
+ struct uniarp *nouap, *ipuap;
+ char abuf[64];
+
+#ifdef DIAGNOSTIC
+ strncpy(abuf, unisig_addr_print(atmsub), sizeof(abuf));
+ ATM_DEBUG4("cache_svc: ip=%s, atm=(%s,%s), origin=%d\n",
+ inet_ntoa(*ip), unisig_addr_print(atm), abuf, origin);
+#endif
+
+ /*
+ * Get interface info
+ */
+ inp = uip->uip_ipnif;
+
+ /*
+ * Find both cached entry and 'nomap' entries for this data.
+ */
+ UNIARP_LOOKUP(ip->s_addr, ipuap);
+ for (nouap = uniarp_nomaptab; nouap; nouap = nouap->ua_next) {
+ if (ATM_ADDR_EQUAL(atm, &nouap->ua_dstatm) &&
+ ATM_ADDR_EQUAL(atmsub, &nouap->ua_dstatmsub) &&
+ (nouap->ua_intf == uip))
+ break;
+ }
+
+ /*
+ * If there aren't any entries yet, create one
+ */
+ if ((ipuap == NULL) && (nouap == NULL)) {
+ ipuap = (struct uniarp *)atm_allocate(&uniarp_pool);
+ if (ipuap == NULL)
+ return (ENOMEM);
+ ipuap->ua_dstip.s_addr = ip->s_addr;
+ ipuap->ua_dstatm.address_format = T_ATM_ABSENT;
+ ipuap->ua_dstatmsub.address_format = T_ATM_ABSENT;
+ ipuap->ua_intf = uip;
+ UNIARP_ADD(ipuap);
+ }
+
+ /*
+ * If there's no cached mapping, then make the 'nomap' entry
+ * the new cached entry.
+ */
+ if (ipuap == NULL) {
+ UNLINK(nouap, struct uniarp, uniarp_nomaptab, ua_next);
+ nouap->ua_dstip.s_addr = ip->s_addr;
+ ipuap = nouap;
+ nouap = NULL;
+ UNIARP_ADD(ipuap);
+ }
+
+ /*
+ * We need to check the consistency of the new data with any
+ * cached data. So taking the easy case first, if there isn't
+ * an ATM address in the cache then we can skip all these checks.
+ */
+ if (ipuap->ua_dstatm.address_format != T_ATM_ABSENT) {
+ /*
+ * See if the new data conflicts with what's in the cache
+ */
+ if (ATM_ADDR_EQUAL(atm, &ipuap->ua_dstatm) &&
+ ATM_ADDR_EQUAL(atmsub, &ipuap->ua_dstatmsub) &&
+ (uip == ipuap->ua_intf)) {
+ /*
+ * No conflicts here
+ */
+ goto dataok;
+ }
+
+ /*
+ * Data conflict...how we deal with this depends on
+ * the origins of the conflicting data
+ */
+ if (origin == ipuap->ua_origin) {
+ /*
+ * The new data has equal precedence - if there are
+ * any VCCs using this entry, then we reject this
+ * "duplicate IP address" update.
+ */
+ if (ipuap->ua_ivp != NULL) {
+ strncpy(abuf, unisig_addr_print(atmsub),
+ sizeof(abuf));
+ log(LOG_WARNING,
+ "uniarp: duplicate IP address %s from %s,%s\n",
+ inet_ntoa(*ip), unisig_addr_print(atm),
+ abuf);
+ return (EACCES);
+ }
+
+ } else if (origin > ipuap->ua_origin) {
+ /*
+ * New data's origin has higher precedence,
+ * so accept the new mapping and notify IP/ATM
+ * that a mapping change has occurred. IP/ATM will
+ * close any VCC's which aren't waiting for this map.
+ */
+ ipuap->ua_flags |= UAF_LOCKED;
+ for (ivp = ipuap->ua_ivp; ivp; ivp = inext) {
+ inext = ivp->iv_arpnext;
+ (*inp->inf_arpnotify)(ivp, MAP_CHANGED);
+ }
+ ipuap->ua_flags &= ~UAF_LOCKED;
+ } else {
+ /*
+ * New data is of lesser origin precedence,
+ * so we just reject the update attempt.
+ */
+ return (EACCES);
+ }
+
+ strncpy(abuf, unisig_addr_print(atmsub), sizeof(abuf));
+ log(LOG_WARNING,
+ "uniarp: ATM address for %s changed to %s,%s\n",
+ inet_ntoa(*ip), unisig_addr_print(atm), abuf);
+ }
+
+ /*
+ * Update the cache entry with the new data
+ */
+ ATM_ADDR_COPY(atm, &ipuap->ua_dstatm);
+ ATM_ADDR_COPY(atmsub, &ipuap->ua_dstatmsub);
+ ipuap->ua_intf = uip;
+
+dataok:
+ /*
+ * Update cache data origin
+ */
+ ipuap->ua_origin = MAX(ipuap->ua_origin, origin);
+
+ /*
+ * Ok, now act on this new/updated cache data
+ */
+ ipuap->ua_flags |= UAF_LOCKED;
+
+ /*
+ * Save pointer to last VCC currently on cached entry chain that
+ * will need to be notified of the map becoming valid
+ */
+ itail = NULL;
+ if ((ipuap->ua_flags & UAF_VALID) == 0) {
+
+ for (itail = ipuap->ua_ivp; itail && itail->iv_arpnext;
+ itail = itail->iv_arpnext) {
+ }
+ }
+
+ /*
+ * If there was a 'nomap' entry for this mapping, then we need to
+ * announce the new mapping to them first.
+ */
+ if (nouap) {
+
+ /*
+ * Move the VCCs from this entry to the cache entry and
+ * let them know there's a valid mapping now
+ */
+ for (ivp = nouap->ua_ivp; ivp; ivp = inext) {
+ inext = ivp->iv_arpnext;
+
+ UNLINK(ivp, struct ipvcc, nouap->ua_ivp, iv_arpnext);
+
+ LINK2TAIL(ivp, struct ipvcc, ipuap->ua_ivp, iv_arpnext);
+ ivp->iv_arpent = (struct arpmap *)ipuap;
+
+ (*inp->inf_arpnotify)(ivp, MAP_VALID);
+ }
+
+ /*
+ * Unlink and free the 'nomap' entry
+ */
+ UNLINK(nouap, struct uniarp, uniarp_nomaptab, ua_next);
+ UNIARP_CANCEL(nouap);
+ atm_free((caddr_t)nouap);
+ }
+
+ /*
+ * Now, if this entry wasn't valid, notify the remaining VCCs
+ */
+ if (itail) {
+
+ for (ivp = ipuap->ua_ivp; ivp; ivp = inext) {
+ inext = ivp->iv_arpnext;
+ (*inp->inf_arpnotify)(ivp, MAP_VALID);
+ if (ivp == itail)
+ break;
+ }
+ }
+ ipuap->ua_flags &= ~UAF_LOCKED;
+
+ /*
+ * We now have a valid cache entry, so cancel any retry timer
+ * and reset the aging timeout
+ */
+ UNIARP_CANCEL(ipuap);
+ if ((ipuap->ua_origin == UAO_REGISTER) && (origin != UAO_REGISTER)) {
+ if (((ipuap->ua_flags & UAF_VALID) == 0) ||
+ (ipuap->ua_aging <=
+ UNIARP_SERVER_AGE - UNIARP_MIN_REFRESH)) {
+ ipuap->ua_flags |= UAF_REFRESH;
+ ipuap->ua_aging = UNIARP_SERVER_AGE;
+ ipuap->ua_retry = UNIARP_SERVER_RETRY;
+ }
+ } else {
+ if (uip->uip_arpstate == UIAS_SERVER_ACTIVE) {
+ ipuap->ua_aging = UNIARP_SERVER_AGE;
+ ipuap->ua_retry = UNIARP_SERVER_RETRY;
+ } else {
+ ipuap->ua_aging = UNIARP_CLIENT_AGE;
+ ipuap->ua_retry = UNIARP_CLIENT_RETRY;
+ }
+ ipuap->ua_flags |= UAF_REFRESH;
+ }
+ ipuap->ua_flags |= UAF_VALID;
+ ipuap->ua_flags &= ~UAF_USED;
+ return (0);
+}
+
+
+/*
+ * Process ARP data from a PVC
+ *
+ * The arp table cache is never updated with PVC information.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * ivp pointer to input PVC's IPVCC control block
+ * ip pointer to IP address structure
+ * atm pointer to ATM address structure
+ * atmsub pointer to ATM subaddress structure
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+uniarp_cache_pvc(ivp, ip, atm, atmsub)
+ struct ipvcc *ivp;
+ struct in_addr *ip;
+ Atm_addr *atm;
+ Atm_addr *atmsub;
+{
+ struct ip_nif *inp;
+ struct uniarp *uap;
+
+#ifdef DIAGNOSTIC
+ char buf[64];
+ int vpi = 0, vci = 0;
+
+ if ((ivp->iv_conn) && (ivp->iv_conn->co_connvc)) {
+ vpi = ivp->iv_conn->co_connvc->cvc_vcc->vc_vpi;
+ vci = ivp->iv_conn->co_connvc->cvc_vcc->vc_vci;
+ }
+ strncpy(buf, unisig_addr_print(atmsub), sizeof(buf));
+ ATM_DEBUG5("cache_pvc: vcc=(%d,%d), ip=%s, atm=(%s,%s)\n",
+ vpi, vci, inet_ntoa(*ip), unisig_addr_print(atm), buf);
+#endif
+
+ /*
+ * Get PVC info
+ */
+ inp = ivp->iv_ipnif;
+ uap = (struct uniarp *)ivp->iv_arpent;
+
+ /*
+ * See if IP address for PVC has changed
+ */
+ if (uap->ua_dstip.s_addr != ip->s_addr) {
+ if (uap->ua_dstip.s_addr != 0)
+ (*inp->inf_arpnotify)(ivp, MAP_CHANGED);
+ uap->ua_dstip.s_addr = ip->s_addr;
+ }
+
+ /*
+ * Let IP/ATM know if address has become valid
+ */
+ if ((uap->ua_flags & UAF_VALID) == 0)
+ (*inp->inf_arpnotify)(ivp, MAP_VALID);
+ uap->ua_flags |= UAF_VALID;
+ uap->ua_aging = UNIARP_CLIENT_AGE;
+ uap->ua_retry = UNIARP_CLIENT_RETRY;
+
+ /*
+ * Save ATM addresses just for debugging
+ */
+ ATM_ADDR_COPY(atm, &uap->ua_dstatm);
+ ATM_ADDR_COPY(atmsub, &uap->ua_dstatmsub);
+
+ return;
+}
+
+
+/*
+ * Validate IP address
+ *
+ * Arguments:
+ * uip pointer to UNI IP interface
+ * ip pointer to IP address structure
+ * origin source of arp information
+ *
+ * Returns:
+ * 0 IP address is acceptable
+ * else invalid IP address
+ *
+ */
+int
+uniarp_validate_ip(uip, ip, origin)
+ struct uniip *uip;
+ struct in_addr *ip;
+ u_int origin;
+{
+ struct uniarp_prf *upp;
+ int i;
+
+
+ /*
+ * Can't be multicast or broadcast address
+ */
+ if (IN_MULTICAST(ntohl(ip->s_addr)) ||
+#if (defined(BSD) && (BSD >= 199306))
+ in_broadcast(*ip, &uip->uip_ipnif->inf_nif->nif_if))
+#else
+ in_broadcast(*ip))
+#endif
+ return (1);
+
+ /*
+ * For ATMARP registration information (including SCSP data),
+ * the address must be allowed by the interface's prefix list.
+ */
+ if ((origin == UAO_REGISTER) || (origin == UAO_SCSP)) {
+ for (i = uip->uip_nprefix, upp = uip->uip_prefix;
+ i; i--, upp++) {
+ if ((ip->s_addr & upp->upf_mask.s_addr) ==
+ upp->upf_addr.s_addr)
+ break;
+ }
+ if (i == 0)
+ return (1);
+ }
+
+ return (0);
+}
+
diff --git a/sys/netatm/uni/uniarp_input.c b/sys/netatm/uni/uniarp_input.c
new file mode 100644
index 0000000..cceeaa9
--- /dev/null
+++ b/sys/netatm/uni/uniarp_input.c
@@ -0,0 +1,853 @@
+/*
+ *
+ * ===================================
+ * 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: uniarp_input.c,v 1.10 1998/07/13 00:04:32 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * UNI ATMARP support (RFC1577) - Input packet processing
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: uniarp_input.c,v 1.10 1998/07/13 00:04:32 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/ipatm/ipatm_var.h>
+#include <netatm/ipatm/ipatm_serv.h>
+#include <netatm/uni/unisig_var.h>
+#include <netatm/uni/uniip_var.h>
+
+
+/*
+ * Local functions
+ */
+static void proc_arp_req __P((struct ipvcc *, KBuffer *));
+static void proc_arp_rsp __P((struct ipvcc *, KBuffer *));
+static void proc_arp_nak __P((struct ipvcc *, KBuffer *));
+static void proc_inarp_req __P((struct ipvcc *, KBuffer *));
+static void proc_inarp_rsp __P((struct ipvcc *, KBuffer *));
+
+
+/*
+ * Local variables
+ */
+static Atm_addr satm;
+static Atm_addr satmsub;
+static Atm_addr tatm;
+static Atm_addr tatmsub;
+static struct in_addr sip;
+static struct in_addr tip;
+
+
+/*
+ * Process ATMARP Input Data
+ *
+ * Arguments:
+ * tok uniarp connection token (pointer to ipvcc)
+ * m pointer to input packet buffer chain
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+uniarp_cpcs_data(tok, m)
+ void *tok;
+ KBuffer *m;
+{
+ struct ipvcc *ivp = tok;
+ struct atmarp_hdr *ahp;
+ KBuffer *n;
+ int len, plen = sizeof(struct atmarp_hdr);
+
+#ifdef DIAGNOSTIC
+ if (uniarp_print)
+ uniarp_pdu_print(ivp, m, "receive");
+#endif
+
+ /*
+ * Verify IP's VCC state
+ */
+ if (ivp->iv_state != IPVCC_ACTIVE) {
+ goto bad;
+ }
+
+ /*
+ * Get the fixed fields together
+ */
+ if (KB_LEN(m) < sizeof(struct atmarp_hdr)) {
+ KB_PULLUP(m, sizeof(struct atmarp_hdr), m);
+ if (m == NULL)
+ goto bad;
+ }
+
+ KB_DATASTART(m, ahp, struct atmarp_hdr *);
+
+ /*
+ * Initial packet verification
+ */
+ if ((ahp->ah_hrd != htons(ARP_ATMFORUM)) ||
+ (ahp->ah_pro != htons(ETHERTYPE_IP)))
+ goto bad;
+
+ /*
+ * Verify/gather source address fields
+ */
+ if (len = (ahp->ah_shtl & ARP_TL_LMASK)) {
+ if (ahp->ah_shtl & ARP_TL_E164) {
+ if (len > sizeof(struct atm_addr_e164))
+ goto bad;
+ satm.address_format = T_ATM_E164_ADDR;
+ } else {
+ if (len != sizeof(struct atm_addr_nsap))
+ goto bad;
+ satm.address_format = T_ATM_ENDSYS_ADDR;
+ }
+ satm.address_length = len;
+ if (KB_COPYDATA(m, plen, len, (caddr_t)satm.address))
+ goto bad;
+ plen += len;
+ } else {
+ satm.address_format = T_ATM_ABSENT;
+ satm.address_length = 0;
+ }
+
+ if (len = (ahp->ah_sstl & ARP_TL_LMASK)) {
+ if (((ahp->ah_sstl & ARP_TL_TMASK) != ARP_TL_NSAPA) ||
+ (len != sizeof(struct atm_addr_nsap)))
+ goto bad;
+ satmsub.address_format = T_ATM_ENDSYS_ADDR;
+ satmsub.address_length = len;
+ if (KB_COPYDATA(m, plen, len, (caddr_t)satmsub.address))
+ goto bad;
+ plen += len;
+ } else {
+ satmsub.address_format = T_ATM_ABSENT;
+ satmsub.address_length = 0;
+ }
+
+ if (len = ahp->ah_spln) {
+ if (len != sizeof(struct in_addr))
+ goto bad;
+ if (KB_COPYDATA(m, plen, len, (caddr_t)&sip))
+ goto bad;
+ plen += len;
+ } else {
+ sip.s_addr = 0;
+ }
+
+ /*
+ * Verify/gather target address fields
+ */
+ if (len = (ahp->ah_thtl & ARP_TL_LMASK)) {
+ if (ahp->ah_thtl & ARP_TL_E164) {
+ if (len > sizeof(struct atm_addr_e164))
+ goto bad;
+ tatm.address_format = T_ATM_E164_ADDR;
+ } else {
+ if (len != sizeof(struct atm_addr_nsap))
+ goto bad;
+ tatm.address_format = T_ATM_ENDSYS_ADDR;
+ }
+ tatm.address_length = len;
+ if (KB_COPYDATA(m, plen, len, (caddr_t)tatm.address))
+ goto bad;
+ plen += len;
+ } else {
+ tatm.address_format = T_ATM_ABSENT;
+ tatm.address_length = 0;
+ }
+
+ if (len = (ahp->ah_tstl & ARP_TL_LMASK)) {
+ if (((ahp->ah_tstl & ARP_TL_TMASK) != ARP_TL_NSAPA) ||
+ (len != sizeof(struct atm_addr_nsap)))
+ goto bad;
+ tatmsub.address_format = T_ATM_ENDSYS_ADDR;
+ tatmsub.address_length = len;
+ if (KB_COPYDATA(m, plen, len, (caddr_t)tatmsub.address))
+ goto bad;
+ plen += len;
+ } else {
+ tatmsub.address_format = T_ATM_ABSENT;
+ tatmsub.address_length = 0;
+ }
+
+ if (len = ahp->ah_tpln) {
+ if (len != sizeof(struct in_addr))
+ goto bad;
+ if (KB_COPYDATA(m, plen, len, (caddr_t)&tip))
+ goto bad;
+ plen += len;
+ } else {
+ tip.s_addr = 0;
+ }
+
+ /*
+ * Verify packet length
+ */
+ for (len = 0, n = m; n; n = KB_NEXT(n))
+ len += KB_LEN(n);
+ if (len != plen)
+ goto bad;
+
+ /*
+ * Now finish with packet-specific processing
+ */
+ switch (ntohs(ahp->ah_op)) {
+ case ARP_REQUEST:
+ proc_arp_req(ivp, m);
+ break;
+
+ case ARP_REPLY:
+ proc_arp_rsp(ivp, m);
+ break;
+
+ case INARP_REQUEST:
+ proc_inarp_req(ivp, m);
+ break;
+
+ case INARP_REPLY:
+ proc_inarp_rsp(ivp, m);
+ break;
+
+ case ARP_NAK:
+ proc_arp_nak(ivp, m);
+ break;
+
+ default:
+ goto bad;
+ }
+
+ return;
+
+bad:
+ uniarp_stat.uas_rcvdrop++;
+ if (m)
+ KB_FREEALL(m);
+}
+
+
+/*
+ * Process an ATMARP request packet
+ *
+ * Arguments:
+ * ivp pointer to input VCC's IPVCC control block
+ * m pointer to input packet buffer chain
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+proc_arp_req(ivp, m)
+ struct ipvcc *ivp;
+ KBuffer *m;
+{
+ struct ip_nif *inp;
+ struct atm_nif *nip;
+ struct siginst *sgp;
+ struct uniip *uip;
+ struct uniarp *uap;
+ struct in_addr myip;
+ int s = splnet();
+
+ /*
+ * Only an arp server should receive these
+ */
+ inp = ivp->iv_ipnif;
+ nip = inp->inf_nif;
+ uip = (struct uniip *)inp->inf_isintf;
+ if ((uip == NULL) ||
+ (uip->uip_arpstate != UIAS_SERVER_ACTIVE))
+ goto drop;
+
+ /*
+ * These should be sent only on SVCs
+ */
+ if ((ivp->iv_flags & IVF_SVC) == 0)
+ goto drop;
+
+ /*
+ * Locate our addresses
+ */
+ sgp = nip->nif_pif->pif_siginst;
+ myip.s_addr = IA_SIN(inp->inf_addr)->sin_addr.s_addr;
+
+ /*
+ * Target IP address must be present
+ */
+ if (tip.s_addr == 0)
+ goto drop;
+
+ /*
+ * Drop packet if both Source addresses aren't present
+ */
+ if ((sip.s_addr == 0) || (satm.address_format == T_ATM_ABSENT))
+ goto drop;
+
+ /*
+ * Source addresses can't be ours
+ */
+ if (ATM_ADDR_SEL_EQUAL(&sgp->si_addr, nip->nif_sel, &satm) &&
+ ATM_ADDR_SEL_EQUAL(&sgp->si_subaddr, nip->nif_sel, &satmsub)) {
+ struct vccb *vcp = ivp->iv_conn->co_connvc->cvc_vcc;
+
+ log(LOG_WARNING,
+ "uniarp: vcc=(%d,%d) reports our ATM address\n",
+ vcp->vc_vpi, vcp->vc_vci);
+ goto drop;
+ }
+ if (sip.s_addr == myip.s_addr) {
+ struct vccb *vcp = ivp->iv_conn->co_connvc->cvc_vcc;
+
+ log(LOG_WARNING,
+ "uniarp: vcc=(%d,%d) reports our IP address\n",
+ vcp->vc_vpi, vcp->vc_vci);
+ goto drop;
+ }
+
+ /*
+ * Validate Source IP address
+ */
+ if (uniarp_validate_ip(uip, &sip, UAO_REGISTER) != 0)
+ goto drop;
+
+ /*
+ * If the source and target IP addresses are the same, then this
+ * must be a client registration request (RFC-2225). Otherwise,
+ * try to accomodate old clients (per RFC-2225 8.4.4).
+ */
+ if (sip.s_addr == tip.s_addr)
+ (void) uniarp_cache_svc(uip, &sip, &satm, &satmsub,
+ UAO_REGISTER);
+ else {
+ uap = (struct uniarp *)ivp->iv_arpent;
+ if ((uap == NULL) || (uap->ua_origin < UAO_REGISTER))
+ (void) uniarp_cache_svc(uip, &sip, &satm, &satmsub,
+ UAO_REGISTER);
+ }
+
+ /*
+ * Lookup the target IP address in the cache (and also check if
+ * the query is for our address).
+ */
+ UNIARP_LOOKUP(tip.s_addr, uap);
+ if (uap && (uap->ua_flags & UAF_VALID)) {
+ /*
+ * We've found a valid mapping
+ */
+ (void) uniarp_arp_rsp(uip, &uap->ua_arpmap, &sip, &satm,
+ &satmsub, ivp);
+
+ } else if (tip.s_addr == myip.s_addr) {
+ /*
+ * We're the target, so respond accordingly
+ */
+ (void) uniarp_arp_rsp(uip, &uip->uip_arpsvrmap, &sip, &satm,
+ &satmsub, ivp);
+
+ } else {
+ /*
+ * We don't know who the target is, so NAK the query
+ */
+ (void) uniarp_arp_nak(uip, m, ivp);
+ m = NULL;
+ }
+
+drop:
+ (void) splx(s);
+ if (m)
+ KB_FREEALL(m);
+ return;
+}
+
+
+/*
+ * Process an ATMARP reply packet
+ *
+ * Arguments:
+ * ivp pointer to input VCC's IPVCC control block
+ * m pointer to input packet buffer chain
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+proc_arp_rsp(ivp, m)
+ struct ipvcc *ivp;
+ KBuffer *m;
+{
+ struct ip_nif *inp;
+ struct atm_nif *nip;
+ struct siginst *sgp;
+ struct uniip *uip;
+ struct uniarp *uap;
+ struct in_addr myip;
+ int s = splnet();
+
+ /*
+ * Only the arp server should send these
+ */
+ inp = ivp->iv_ipnif;
+ nip = inp->inf_nif;
+ uip = (struct uniip *)inp->inf_isintf;
+ if ((uip == NULL) ||
+ (uip->uip_arpsvrvcc != ivp))
+ goto drop;
+
+ /*
+ * Locate our addresses
+ */
+ sgp = nip->nif_pif->pif_siginst;
+ myip.s_addr = IA_SIN(inp->inf_addr)->sin_addr.s_addr;
+
+ /*
+ * Target addresses must be ours
+ */
+ if ((tip.s_addr != myip.s_addr) ||
+ !ATM_ADDR_SEL_EQUAL(&sgp->si_addr, nip->nif_sel, &tatm) ||
+ !ATM_ADDR_SEL_EQUAL(&sgp->si_subaddr, nip->nif_sel, &tatmsub))
+ goto drop;
+
+ /*
+ * Drop packet if both Source addresses aren't present
+ */
+ if ((sip.s_addr == 0) || (satm.address_format == T_ATM_ABSENT))
+ goto drop;
+
+ /*
+ * If the Source addresses are ours, this is an arp server
+ * registration response
+ */
+ if (ATM_ADDR_SEL_EQUAL(&sgp->si_addr, nip->nif_sel, &satm) &&
+ ATM_ADDR_SEL_EQUAL(&sgp->si_subaddr, nip->nif_sel, &satmsub)) {
+ if (sip.s_addr == myip.s_addr) {
+ /*
+ * Registration response - update our state and
+ * set a registration refresh timer
+ */
+ if (uip->uip_arpstate == UIAS_CLIENT_REGISTER)
+ uip->uip_arpstate = UIAS_CLIENT_ACTIVE;
+
+ if (uip->uip_arpstate == UIAS_CLIENT_ACTIVE) {
+ UNIIP_ARP_CANCEL(uip);
+ UNIIP_ARP_TIMER(uip, UNIARP_REGIS_REFRESH);
+ }
+
+ /*
+ * If the cache entry for the server VCC isn't valid
+ * yet, then send an Inverse ATMARP request to solicit
+ * the server's IP address
+ */
+ uap = (struct uniarp *)ivp->iv_arpent;
+ if ((uap->ua_flags & UAF_VALID) == 0) {
+ (void) uniarp_inarp_req(uip, &uap->ua_dstatm,
+ &uap->ua_dstatmsub, ivp);
+ }
+ goto drop;
+ } else {
+ log(LOG_WARNING,
+ "uniarp: arpserver has our IP address wrong\n");
+ goto drop;
+ }
+ } else if (sip.s_addr == myip.s_addr) {
+ log(LOG_WARNING,
+ "uniarp: arpserver has our ATM address wrong\n");
+ goto drop;
+ }
+
+ /*
+ * Validate the Source IP address
+ */
+ if (uniarp_validate_ip(uip, &sip, UAO_LOOKUP) != 0)
+ goto drop;
+
+ /*
+ * Now we believe this packet contains an authoritative mapping,
+ * which we probably need to setup an outgoing SVC connection
+ */
+ (void) uniarp_cache_svc(uip, &sip, &satm, &satmsub, UAO_LOOKUP);
+
+drop:
+ (void) splx(s);
+ KB_FREEALL(m);
+ return;
+}
+
+
+/*
+ * Process an ATMARP negative ack packet
+ *
+ * Arguments:
+ * ivp pointer to input VCC's IPVCC control block
+ * m pointer to input packet buffer chain
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+proc_arp_nak(ivp, m)
+ struct ipvcc *ivp;
+ KBuffer *m;
+{
+ struct ip_nif *inp;
+ struct atm_nif *nip;
+ struct siginst *sgp;
+ struct uniip *uip;
+ struct uniarp *uap;
+ struct in_addr myip;
+ struct ipvcc *inext;
+ int s = splnet();
+
+ /*
+ * Only the arp server should send these
+ */
+ inp = ivp->iv_ipnif;
+ nip = inp->inf_nif;
+ uip = (struct uniip *)inp->inf_isintf;
+ if ((uip == NULL) ||
+ (uip->uip_arpsvrvcc != ivp))
+ goto drop;
+
+ /*
+ * Locate our addresses
+ */
+ sgp = nip->nif_pif->pif_siginst;
+ myip.s_addr = IA_SIN(inp->inf_addr)->sin_addr.s_addr;
+
+ /*
+ * Source addresses must be ours
+ */
+ if ((sip.s_addr != myip.s_addr) ||
+ !ATM_ADDR_SEL_EQUAL(&sgp->si_addr, nip->nif_sel, &satm) ||
+ !ATM_ADDR_SEL_EQUAL(&sgp->si_subaddr, nip->nif_sel, &satmsub))
+ goto drop;
+
+ /*
+ * Drop packet if the Target IP address isn't there or if this
+ * is a registration response, indicating an old or flakey server
+ */
+ if ((tip.s_addr == 0) || (tip.s_addr == myip.s_addr))
+ goto drop;
+
+ /*
+ * Otherwise, see who we were looking for
+ */
+ UNIARP_LOOKUP(tip.s_addr, uap);
+ if (uap == NULL)
+ goto drop;
+
+ /*
+ * This entry isn't valid any longer, so notify all VCCs using this
+ * entry that they must finish up. The last notify should cause
+ * this entry to be freed by the vcclose() function.
+ */
+ uap->ua_flags &= ~UAF_VALID;
+ for (ivp = uap->ua_ivp; ivp; ivp = inext) {
+ inext = ivp->iv_arpnext;
+ (*inp->inf_arpnotify)(ivp, MAP_FAILED);
+ }
+
+drop:
+ (void) splx(s);
+ KB_FREEALL(m);
+ return;
+}
+
+
+/*
+ * Process an InATMARP request packet
+ *
+ * Arguments:
+ * ivp pointer to input VCC's IPVCC control block
+ * m pointer to input packet buffer chain
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+proc_inarp_req(ivp, m)
+ struct ipvcc *ivp;
+ KBuffer *m;
+{
+ struct ip_nif *inp;
+ struct atm_nif *nip;
+ struct siginst *sgp;
+ struct uniip *uip;
+ struct in_addr myip;
+ int s = splnet();
+
+ /*
+ * Get interface pointers
+ */
+ inp = ivp->iv_ipnif;
+ nip = inp->inf_nif;
+ uip = (struct uniip *)inp->inf_isintf;
+ if (uip == NULL)
+ goto drop;
+
+ /*
+ * Locate our addresses
+ */
+ sgp = nip->nif_pif->pif_siginst;
+ myip.s_addr = IA_SIN(inp->inf_addr)->sin_addr.s_addr;
+
+ /*
+ * Packet must have a Source IP address and, if it was received
+ * over an SVC, a Source ATM address too.
+ */
+ if ((sip.s_addr == 0) ||
+ ((ivp->iv_flags & IVF_SVC) && (satm.address_format == T_ATM_ABSENT)))
+ goto drop;
+
+ /*
+ * Validate Source ATM address
+ * - can't be me
+ */
+ if (satm.address_format != T_ATM_ABSENT) {
+ if (ATM_ADDR_SEL_EQUAL(&sgp->si_addr, nip->nif_sel, &satm) &&
+ ATM_ADDR_SEL_EQUAL(&sgp->si_subaddr, nip->nif_sel,
+ &satmsub))
+ goto drop;
+ }
+
+ /*
+ * Validate Source IP address
+ */
+ if ((sip.s_addr == myip.s_addr) ||
+ (uniarp_validate_ip(uip, &sip, UAO_PEER_REQ) != 0))
+ goto drop;
+
+ /*
+ * The Target ATM address is required for a packet received over
+ * an SVC, optional for a PVC. If one is present, it must be our
+ * address.
+ */
+ if ((ivp->iv_flags & IVF_SVC) && (tatm.address_format == T_ATM_ABSENT))
+ goto drop;
+ if ((tatm.address_format != T_ATM_ABSENT) &&
+ (!ATM_ADDR_SEL_EQUAL(&sgp->si_addr, nip->nif_sel, &tatm) ||
+ !ATM_ADDR_SEL_EQUAL(&sgp->si_subaddr, nip->nif_sel, &tatmsub)))
+ goto drop;
+
+ /*
+ * See where this packet is from
+ */
+ if (ivp->iv_flags & IVF_PVC) {
+ /*
+ * Process the PVC arp data, although we don't really
+ * update the arp cache with this information
+ */
+ uniarp_cache_pvc(ivp, &sip, &satm, &satmsub);
+
+ } else if (uip->uip_arpsvrvcc == ivp) {
+ /*
+ * Packet is from the arp server, so we've received a
+ * registration/refresh request (1577 version).
+ *
+ * Therefore, update cache with authoritative data.
+ */
+ (void) uniarp_cache_svc(uip, &sip, &satm, &satmsub, UAO_LOOKUP);
+
+ /*
+ * Make sure the cache update didn't kill the server VCC
+ */
+ if (uip->uip_arpsvrvcc != ivp)
+ goto drop;
+
+ /*
+ * Update the server state and set the
+ * registration refresh timer
+ */
+ uip->uip_arpstate = UIAS_CLIENT_ACTIVE;
+ UNIIP_ARP_CANCEL(uip);
+ UNIIP_ARP_TIMER(uip, UNIARP_REGIS_REFRESH);
+ } else {
+ /*
+ * Otherwise, we consider this source mapping data as
+ * non-authoritative and update the cache appropriately
+ */
+ if (uniarp_cache_svc(uip, &sip, &satm, &satmsub, UAO_PEER_REQ))
+ goto drop;
+ }
+
+ /*
+ * Send an InATMARP response back to originator
+ */
+ (void) uniarp_inarp_rsp(uip, &sip, &satm, &satmsub, ivp);
+
+drop:
+ (void) splx(s);
+ KB_FREEALL(m);
+ return;
+}
+
+
+/*
+ * Process an InATMARP response packet
+ *
+ * Arguments:
+ * ivp pointer to input VCC's IPVCC control block
+ * m pointer to input packet buffer chain
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+proc_inarp_rsp(ivp, m)
+ struct ipvcc *ivp;
+ KBuffer *m;
+{
+ struct ip_nif *inp;
+ struct atm_nif *nip;
+ struct siginst *sgp;
+ struct uniip *uip;
+ struct uniarp *uap;
+ struct in_addr myip;
+ int s = splnet();
+
+ /*
+ * Get interface pointers
+ */
+ inp = ivp->iv_ipnif;
+ nip = inp->inf_nif;
+ uip = (struct uniip *)inp->inf_isintf;
+ if (uip == NULL)
+ goto drop;
+
+ /*
+ * Locate our addresses
+ */
+ sgp = nip->nif_pif->pif_siginst;
+ myip.s_addr = IA_SIN(inp->inf_addr)->sin_addr.s_addr;
+
+ /*
+ * Packet must have a Source IP address and, if it was received
+ * over an SVC, a Source ATM address too.
+ */
+ if ((sip.s_addr == 0) ||
+ ((ivp->iv_flags & IVF_SVC) && (satm.address_format == T_ATM_ABSENT)))
+ goto drop;
+
+ /*
+ * Validate Source ATM address
+ * - can't be me
+ */
+ if (satm.address_format != T_ATM_ABSENT) {
+ if (ATM_ADDR_SEL_EQUAL(&sgp->si_addr, nip->nif_sel, &satm) &&
+ ATM_ADDR_SEL_EQUAL(&sgp->si_subaddr, nip->nif_sel,
+ &satmsub))
+ goto drop;
+ }
+
+ /*
+ * Validate Source IP address
+ * - must be in our LIS
+ * - can't be me
+ * - can't be broadcast
+ * - can't be multicast
+ */
+ if ((sip.s_addr == myip.s_addr) ||
+ (uniarp_validate_ip(uip, &sip, UAO_PEER_RSP) != 0))
+ goto drop;
+
+ /*
+ * The Target ATM address is required for a packet received over
+ * an SVC, optional for a PVC. If one is present, it must be our
+ * address.
+ */
+ if ((ivp->iv_flags & IVF_SVC) && (tatm.address_format == T_ATM_ABSENT))
+ goto drop;
+ if ((tatm.address_format != T_ATM_ABSENT) &&
+ (!ATM_ADDR_SEL_EQUAL(&sgp->si_addr, nip->nif_sel, &tatm) ||
+ !ATM_ADDR_SEL_EQUAL(&sgp->si_subaddr, nip->nif_sel, &tatmsub)))
+ goto drop;
+
+ /*
+ * See where this packet is from
+ */
+ if (ivp->iv_flags & IVF_PVC) {
+ /*
+ * Process the PVC arp data, although we don't really
+ * update the arp cache with this information
+ */
+ uniarp_cache_pvc(ivp, &sip, &satm, &satmsub);
+
+ } else {
+ /*
+ * Can't tell the difference between an RFC-1577 registration
+ * and a data connection from a client of another arpserver
+ * on our LIS (using SCSP) - so we'll update the cache now
+ * with what we've got. Our clients will get "registered"
+ * when (if) they query us with an arp request.
+ */
+ (void) uniarp_cache_svc(uip, &sip, &satm, &satmsub,
+ UAO_PEER_RSP);
+ }
+
+drop:
+ (void) splx(s);
+ KB_FREEALL(m);
+ return;
+}
+
+
+/*
+ * Print an ATMARP PDU
+ *
+ * Arguments:
+ * ivp pointer to input VCC control block
+ * m pointer to pdu buffer chain
+ * msg pointer to message string
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+uniarp_pdu_print(ivp, m, msg)
+ struct ipvcc *ivp;
+ KBuffer *m;
+ char *msg;
+{
+ char buf[128];
+ struct vccb *vcp;
+
+ vcp = ivp->iv_conn->co_connvc->cvc_vcc;
+ sprintf(buf, "uniarp %s: vcc=(%d,%d)\n", msg, vcp->vc_vpi, vcp->vc_vci);
+ atm_pdu_print(m, buf);
+}
+
diff --git a/sys/netatm/uni/uniarp_output.c b/sys/netatm/uni/uniarp_output.c
new file mode 100644
index 0000000..81fab93
--- /dev/null
+++ b/sys/netatm/uni/uniarp_output.c
@@ -0,0 +1,797 @@
+/*
+ *
+ * ===================================
+ * 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: uniarp_output.c,v 1.7 1998/06/29 22:15:41 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * UNI ATMARP support (RFC1577) - Output packet processing
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: uniarp_output.c,v 1.7 1998/06/29 22:15:41 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/ipatm/ipatm_var.h>
+#include <netatm/ipatm/ipatm_serv.h>
+#include <netatm/uni/uniip_var.h>
+
+
+/*
+ * Issue an ATMARP Request PDU
+ *
+ * Arguments:
+ * uip pointer to IP interface
+ * tip pointer to target IP address
+ *
+ * Returns:
+ * 0 PDU was successfully sent
+ * else unable to send PDU
+ *
+ */
+int
+uniarp_arp_req(uip, tip)
+ struct uniip *uip;
+ struct in_addr *tip;
+{
+ KBuffer *m;
+ struct atmarp_hdr *ahp;
+ struct atm_nif *nip;
+ struct ip_nif *inp;
+ struct ipvcc *ivp;
+ struct siginst *sip;
+ char *cp;
+ int len, err;
+
+ inp = uip->uip_ipnif;
+ nip = inp->inf_nif;
+ sip = inp->inf_nif->nif_pif->pif_siginst;
+
+ /*
+ * Figure out how long pdu is going to be
+ */
+ len = sizeof(struct atmarp_hdr) + (2 * sizeof(struct in_addr));
+ switch (sip->si_addr.address_format) {
+ case T_ATM_ENDSYS_ADDR:
+ len += sip->si_addr.address_length;
+ break;
+
+ case T_ATM_E164_ADDR:
+ len += sip->si_addr.address_length;
+ if (sip->si_subaddr.address_format == T_ATM_ENDSYS_ADDR)
+ len += sip->si_subaddr.address_length;
+ break;
+ }
+
+ /*
+ * Get a buffer for pdu
+ */
+ KB_ALLOCPKT(m, len, KB_F_NOWAIT, KB_T_DATA);
+ if (m == NULL)
+ return (1);
+
+ /*
+ * Place aligned pdu at end of buffer
+ */
+ KB_TAILALIGN(m, len);
+ KB_DATASTART(m, ahp, struct atmarp_hdr *);
+
+ /*
+ * Setup variable fields pointer
+ */
+ cp = (char *)ahp + sizeof(struct atmarp_hdr);
+
+ /*
+ * Build fields
+ */
+ ahp->ah_hrd = htons(ARP_ATMFORUM);
+ ahp->ah_pro = htons(ETHERTYPE_IP);
+ len = sip->si_addr.address_length;
+ switch (sip->si_addr.address_format) {
+ case T_ATM_ENDSYS_ADDR:
+ ahp->ah_shtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
+
+ /* ah_sha */
+ KM_COPY(sip->si_addr.address, cp, len - 1);
+ ((struct atm_addr_nsap *)cp)->aan_sel = nip->nif_sel;
+ cp += len;
+
+ ahp->ah_sstl = 0;
+ break;
+
+ case T_ATM_E164_ADDR:
+ ahp->ah_shtl = ARP_TL_E164 | (len & ARP_TL_LMASK);
+
+ /* ah_sha */
+ KM_COPY(sip->si_addr.address, cp, len);
+ cp += len;
+
+ if (sip->si_subaddr.address_format == T_ATM_ENDSYS_ADDR) {
+ len = sip->si_subaddr.address_length;
+ ahp->ah_sstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
+
+ /* ah_ssa */
+ KM_COPY(sip->si_subaddr.address, cp, len - 1);
+ ((struct atm_addr_nsap *)cp)->aan_sel = nip->nif_sel;
+ cp += len;
+ } else
+ ahp->ah_sstl = 0;
+ break;
+
+ default:
+ ahp->ah_shtl = 0;
+ ahp->ah_sstl = 0;
+ }
+
+ ahp->ah_op = htons(ARP_REQUEST);
+ ahp->ah_spln = sizeof(struct in_addr);
+
+ /* ah_spa */
+ KM_COPY((caddr_t)&(IA_SIN(inp->inf_addr)->sin_addr), cp,
+ sizeof(struct in_addr));
+ cp += sizeof(struct in_addr);
+
+ ahp->ah_thtl = 0;
+ ahp->ah_tstl = 0;
+
+ ahp->ah_tpln = sizeof(struct in_addr);
+
+ /* ah_tpa */
+ KM_COPY((caddr_t)tip, cp, sizeof(struct in_addr));
+
+ /*
+ * Finally, send the pdu to the ATMARP server
+ */
+ ivp = uip->uip_arpsvrvcc;
+ if (uniarp_print)
+ uniarp_pdu_print(ivp, m, "send");
+ err = atm_cm_cpcs_data(ivp->iv_arpconn, m);
+ if (err) {
+ /*
+ * Didn't make it
+ */
+ KB_FREEALL(m);
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * Issue an ATMARP Response PDU
+ *
+ * Arguments:
+ * uip pointer to IP interface
+ * amp pointer to source map entry
+ * tip pointer to target IP address
+ * tatm pointer to target ATM address
+ * tsub pointer to target ATM subaddress
+ * ivp pointer to vcc over which to send pdu
+ *
+ * Returns:
+ * 0 PDU was successfully sent
+ * else unable to send PDU
+ *
+ */
+int
+uniarp_arp_rsp(uip, amp, tip, tatm, tsub, ivp)
+ struct uniip *uip;
+ struct arpmap *amp;
+ struct in_addr *tip;
+ Atm_addr *tatm;
+ Atm_addr *tsub;
+ struct ipvcc *ivp;
+{
+ KBuffer *m;
+ struct atmarp_hdr *ahp;
+ char *cp;
+ int len, err;
+
+ /*
+ * Figure out how long pdu is going to be
+ */
+ len = sizeof(struct atmarp_hdr) + (2 * sizeof(struct in_addr));
+ switch (amp->am_dstatm.address_format) {
+ case T_ATM_ENDSYS_ADDR:
+ len += amp->am_dstatm.address_length;
+ break;
+
+ case T_ATM_E164_ADDR:
+ len += amp->am_dstatm.address_length;
+ if (amp->am_dstatmsub.address_format == T_ATM_ENDSYS_ADDR)
+ len += amp->am_dstatmsub.address_length;
+ break;
+ }
+
+ switch (tatm->address_format) {
+ case T_ATM_ENDSYS_ADDR:
+ len += tatm->address_length;
+ break;
+
+ case T_ATM_E164_ADDR:
+ len += tatm->address_length;
+ if (tsub->address_format == T_ATM_ENDSYS_ADDR)
+ len += tsub->address_length;
+ break;
+ }
+
+ /*
+ * Get a buffer for pdu
+ */
+ KB_ALLOCPKT(m, len, KB_F_NOWAIT, KB_T_DATA);
+ if (m == NULL)
+ return (1);
+
+ /*
+ * Place aligned pdu at end of buffer
+ */
+ KB_TAILALIGN(m, len);
+ KB_DATASTART(m, ahp, struct atmarp_hdr *);
+
+ /*
+ * Setup variable fields pointer
+ */
+ cp = (char *)ahp + sizeof(struct atmarp_hdr);
+
+ /*
+ * Build fields
+ */
+ ahp->ah_hrd = htons(ARP_ATMFORUM);
+ ahp->ah_pro = htons(ETHERTYPE_IP);
+ len = amp->am_dstatm.address_length;
+ switch (amp->am_dstatm.address_format) {
+ case T_ATM_ENDSYS_ADDR:
+ ahp->ah_shtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
+
+ /* ah_sha */
+ KM_COPY(amp->am_dstatm.address, cp, len);
+ cp += len;
+
+ ahp->ah_sstl = 0;
+ break;
+
+ case T_ATM_E164_ADDR:
+ ahp->ah_shtl = ARP_TL_E164 | (len & ARP_TL_LMASK);
+
+ /* ah_sha */
+ KM_COPY(amp->am_dstatm.address, cp, len);
+ cp += len;
+
+ if (amp->am_dstatmsub.address_format == T_ATM_ENDSYS_ADDR) {
+ len = amp->am_dstatmsub.address_length;
+ ahp->ah_sstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
+
+ /* ah_ssa */
+ KM_COPY(amp->am_dstatmsub.address, cp, len);
+ cp += len;
+ } else
+ ahp->ah_sstl = 0;
+ break;
+
+ default:
+ ahp->ah_shtl = 0;
+ ahp->ah_sstl = 0;
+ }
+
+ ahp->ah_op = htons(ARP_REPLY);
+ ahp->ah_spln = sizeof(struct in_addr);
+
+ /* ah_spa */
+ KM_COPY((caddr_t)&amp->am_dstip, cp, sizeof(struct in_addr));
+ cp += sizeof(struct in_addr);
+
+ len = tatm->address_length;
+ switch (tatm->address_format) {
+ case T_ATM_ENDSYS_ADDR:
+ ahp->ah_thtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
+
+ /* ah_tha */
+ KM_COPY(tatm->address, cp, len);
+ cp += len;
+
+ ahp->ah_tstl = 0;
+ break;
+
+ case T_ATM_E164_ADDR:
+ ahp->ah_thtl = ARP_TL_E164 | (len & ARP_TL_LMASK);
+
+ /* ah_tha */
+ KM_COPY(tatm->address, cp, len);
+ cp += len;
+
+ if (tsub->address_format == T_ATM_ENDSYS_ADDR) {
+ len = tsub->address_length;
+ ahp->ah_tstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
+
+ /* ah_tsa */
+ KM_COPY(tsub->address, cp, len);
+ cp += len;
+ } else
+ ahp->ah_tstl = 0;
+ break;
+
+ default:
+ ahp->ah_thtl = 0;
+ ahp->ah_tstl = 0;
+ }
+
+ ahp->ah_tpln = sizeof(struct in_addr);
+
+ /* ah_tpa */
+ KM_COPY((caddr_t)tip, cp, sizeof(struct in_addr));
+
+ /*
+ * Finally, send the pdu to the vcc peer
+ */
+ if (uniarp_print)
+ uniarp_pdu_print(ivp, m, "send");
+ err = atm_cm_cpcs_data(ivp->iv_arpconn, m);
+ if (err) {
+ /*
+ * Didn't make it
+ */
+ KB_FREEALL(m);
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * Issue an ATMARP NAK PDU
+ *
+ * Arguments:
+ * uip pointer to IP interface
+ * m pointer to ATMARP_REQ buffer chain
+ * ivp pointer to vcc over which to send pdu
+ *
+ * Returns:
+ * 0 PDU was successfully sent
+ * else unable to send PDU
+ *
+ */
+int
+uniarp_arp_nak(uip, m, ivp)
+ struct uniip *uip;
+ KBuffer *m;
+ struct ipvcc *ivp;
+{
+ struct atmarp_hdr *ahp;
+ int err;
+
+ /*
+ * Get the fixed fields together
+ */
+ if (KB_LEN(m) < sizeof(struct atmarp_hdr)) {
+ KB_PULLUP(m, sizeof(struct atmarp_hdr), m);
+ if (m == NULL)
+ return (1);
+ }
+ KB_DATASTART(m, ahp, struct atmarp_hdr *);
+
+ /*
+ * Set new op-code
+ */
+ ahp->ah_op = htons(ARP_NAK);
+
+ /*
+ * Finally, send the pdu to the vcc peer
+ */
+ if (uniarp_print)
+ uniarp_pdu_print(ivp, m, "send");
+ err = atm_cm_cpcs_data(ivp->iv_arpconn, m);
+ if (err) {
+ /*
+ * Didn't make it
+ */
+ KB_FREEALL(m);
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * Issue an InATMARP Request PDU
+ *
+ * Arguments:
+ * uip pointer to IP interface
+ * tatm pointer to target ATM address
+ * tsub pointer to target ATM subaddress
+ * ivp pointer to vcc over which to send pdu
+ *
+ * Returns:
+ * 0 PDU was successfully sent
+ * else unable to send PDU
+ *
+ */
+int
+uniarp_inarp_req(uip, tatm, tsub, ivp)
+ struct uniip *uip;
+ Atm_addr *tatm;
+ Atm_addr *tsub;
+ struct ipvcc *ivp;
+{
+ KBuffer *m;
+ struct atmarp_hdr *ahp;
+ struct atm_nif *nip;
+ struct ip_nif *inp;
+ struct siginst *sip;
+ char *cp;
+ int len, err;
+
+ inp = uip->uip_ipnif;
+ nip = inp->inf_nif;
+ sip = inp->inf_nif->nif_pif->pif_siginst;
+
+ /*
+ * Figure out how long pdu is going to be
+ */
+ len = sizeof(struct atmarp_hdr) + sizeof(struct in_addr);
+ switch (sip->si_addr.address_format) {
+ case T_ATM_ENDSYS_ADDR:
+ len += sip->si_addr.address_length;
+ break;
+
+ case T_ATM_E164_ADDR:
+ len += sip->si_addr.address_length;
+ if (sip->si_subaddr.address_format == T_ATM_ENDSYS_ADDR)
+ len += sip->si_subaddr.address_length;
+ break;
+ }
+
+ switch (tatm->address_format) {
+ case T_ATM_ENDSYS_ADDR:
+ len += tatm->address_length;
+ break;
+
+ case T_ATM_E164_ADDR:
+ len += tatm->address_length;
+ if (tsub->address_format == T_ATM_ENDSYS_ADDR)
+ len += tsub->address_length;
+ break;
+ }
+
+ /*
+ * Get a buffer for pdu
+ */
+ KB_ALLOCPKT(m, len, KB_F_NOWAIT, KB_T_DATA);
+ if (m == NULL)
+ return (1);
+
+ /*
+ * Place aligned pdu at end of buffer
+ */
+ KB_TAILALIGN(m, len);
+ KB_DATASTART(m, ahp, struct atmarp_hdr *);
+
+ /*
+ * Setup variable fields pointer
+ */
+ cp = (char *)ahp + sizeof(struct atmarp_hdr);
+
+ /*
+ * Build fields
+ */
+ ahp->ah_hrd = htons(ARP_ATMFORUM);
+ ahp->ah_pro = htons(ETHERTYPE_IP);
+ len = sip->si_addr.address_length;
+ switch (sip->si_addr.address_format) {
+ case T_ATM_ENDSYS_ADDR:
+ ahp->ah_shtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
+
+ /* ah_sha */
+ KM_COPY(sip->si_addr.address, cp, len - 1);
+ ((struct atm_addr_nsap *)cp)->aan_sel = nip->nif_sel;
+ cp += len;
+
+ ahp->ah_sstl = 0;
+ break;
+
+ case T_ATM_E164_ADDR:
+ ahp->ah_shtl = ARP_TL_E164 | (len & ARP_TL_LMASK);
+
+ /* ah_sha */
+ KM_COPY(sip->si_addr.address, cp, len);
+ cp += len;
+
+ if (sip->si_subaddr.address_format == T_ATM_ENDSYS_ADDR) {
+ len = sip->si_subaddr.address_length;
+ ahp->ah_sstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
+
+ /* ah_ssa */
+ KM_COPY(sip->si_subaddr.address, cp, len - 1);
+ ((struct atm_addr_nsap *)cp)->aan_sel = nip->nif_sel;
+ cp += len;
+ } else
+ ahp->ah_sstl = 0;
+ break;
+
+ default:
+ ahp->ah_shtl = 0;
+ ahp->ah_sstl = 0;
+ }
+
+ ahp->ah_op = htons(INARP_REQUEST);
+ ahp->ah_spln = sizeof(struct in_addr);
+
+ /* ah_spa */
+ KM_COPY((caddr_t)&(IA_SIN(inp->inf_addr)->sin_addr), cp,
+ sizeof(struct in_addr));
+ cp += sizeof(struct in_addr);
+
+ len = tatm->address_length;
+ switch (tatm->address_format) {
+ case T_ATM_ENDSYS_ADDR:
+ ahp->ah_thtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
+
+ /* ah_tha */
+ KM_COPY(tatm->address, cp, len);
+ cp += len;
+
+ ahp->ah_tstl = 0;
+ break;
+
+ case T_ATM_E164_ADDR:
+ ahp->ah_thtl = ARP_TL_E164 | (len & ARP_TL_LMASK);
+
+ /* ah_tha */
+ KM_COPY(tatm->address, cp, len);
+ cp += len;
+
+ if (tsub->address_format == T_ATM_ENDSYS_ADDR) {
+ len = tsub->address_length;
+ ahp->ah_tstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
+
+ /* ah_tsa */
+ KM_COPY(tsub->address, cp, len);
+ cp += len;
+ } else
+ ahp->ah_tstl = 0;
+ break;
+
+ default:
+ ahp->ah_thtl = 0;
+ ahp->ah_tstl = 0;
+ }
+
+ ahp->ah_tpln = 0;
+
+ /*
+ * Finally, send the pdu to the vcc peer
+ */
+ if (uniarp_print)
+ uniarp_pdu_print(ivp, m, "send");
+ err = atm_cm_cpcs_data(ivp->iv_arpconn, m);
+ if (err) {
+ /*
+ * Didn't make it
+ */
+ KB_FREEALL(m);
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * Issue an InATMARP Response PDU
+ *
+ * Arguments:
+ * uip pointer to IP interface
+ * tip pointer to target IP address
+ * tatm pointer to target ATM address
+ * tsub pointer to target ATM subaddress
+ * ivp pointer to vcc over which to send pdu
+ *
+ * Returns:
+ * 0 PDU was successfully sent
+ * else unable to send PDU
+ *
+ */
+int
+uniarp_inarp_rsp(uip, tip, tatm, tsub, ivp)
+ struct uniip *uip;
+ struct in_addr *tip;
+ Atm_addr *tatm;
+ Atm_addr *tsub;
+ struct ipvcc *ivp;
+{
+ KBuffer *m;
+ struct atmarp_hdr *ahp;
+ struct atm_nif *nip;
+ struct ip_nif *inp;
+ struct siginst *sip;
+ char *cp;
+ int len, err;
+
+ inp = uip->uip_ipnif;
+ nip = inp->inf_nif;
+ sip = inp->inf_nif->nif_pif->pif_siginst;
+
+ /*
+ * Figure out how long pdu is going to be
+ */
+ len = sizeof(struct atmarp_hdr) + (2 * sizeof(struct in_addr));
+ switch (sip->si_addr.address_format) {
+ case T_ATM_ENDSYS_ADDR:
+ len += sip->si_addr.address_length;
+ break;
+
+ case T_ATM_E164_ADDR:
+ len += sip->si_addr.address_length;
+ if (sip->si_subaddr.address_format == T_ATM_ENDSYS_ADDR)
+ len += sip->si_subaddr.address_length;
+ break;
+ }
+
+ switch (tatm->address_format) {
+ case T_ATM_ENDSYS_ADDR:
+ len += tatm->address_length;
+ break;
+
+ case T_ATM_E164_ADDR:
+ len += tatm->address_length;
+ if (tsub->address_format == T_ATM_ENDSYS_ADDR)
+ len += tsub->address_length;
+ break;
+ }
+
+ /*
+ * Get a buffer for pdu
+ */
+ KB_ALLOCPKT(m, len, KB_F_NOWAIT, KB_T_DATA);
+ if (m == NULL)
+ return (1);
+
+ /*
+ * Place aligned pdu at end of buffer
+ */
+ KB_TAILALIGN(m, len);
+ KB_DATASTART(m, ahp, struct atmarp_hdr *);
+
+ /*
+ * Setup variable fields pointer
+ */
+ cp = (char *)ahp + sizeof(struct atmarp_hdr);
+
+ /*
+ * Build fields
+ */
+ ahp->ah_hrd = htons(ARP_ATMFORUM);
+ ahp->ah_pro = htons(ETHERTYPE_IP);
+ len = sip->si_addr.address_length;
+ switch (sip->si_addr.address_format) {
+ case T_ATM_ENDSYS_ADDR:
+ ahp->ah_shtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
+
+ /* ah_sha */
+ KM_COPY(sip->si_addr.address, cp, len - 1);
+ ((struct atm_addr_nsap *)cp)->aan_sel = nip->nif_sel;
+ cp += len;
+
+ ahp->ah_sstl = 0;
+ break;
+
+ case T_ATM_E164_ADDR:
+ ahp->ah_shtl = ARP_TL_E164 | (len & ARP_TL_LMASK);
+
+ /* ah_sha */
+ KM_COPY(sip->si_addr.address, cp, len);
+ cp += len;
+
+ if (sip->si_subaddr.address_format == T_ATM_ENDSYS_ADDR) {
+ len = sip->si_subaddr.address_length;
+ ahp->ah_sstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
+
+ /* ah_ssa */
+ KM_COPY(sip->si_subaddr.address, cp, len - 1);
+ ((struct atm_addr_nsap *)cp)->aan_sel = nip->nif_sel;
+ cp += len;
+ } else
+ ahp->ah_sstl = 0;
+ break;
+
+ default:
+ ahp->ah_shtl = 0;
+ ahp->ah_sstl = 0;
+ }
+
+ ahp->ah_op = htons(INARP_REPLY);
+ ahp->ah_spln = sizeof(struct in_addr);
+
+ /* ah_spa */
+ KM_COPY((caddr_t)&(IA_SIN(inp->inf_addr)->sin_addr), cp,
+ sizeof(struct in_addr));
+ cp += sizeof(struct in_addr);
+
+ len = tatm->address_length;
+ switch (tatm->address_format) {
+ case T_ATM_ENDSYS_ADDR:
+ ahp->ah_thtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
+
+ /* ah_tha */
+ KM_COPY(tatm->address, cp, len);
+ cp += len;
+
+ ahp->ah_tstl = 0;
+ break;
+
+ case T_ATM_E164_ADDR:
+ ahp->ah_thtl = ARP_TL_E164 | (len & ARP_TL_LMASK);
+
+ /* ah_tha */
+ KM_COPY(tatm->address, cp, len);
+ cp += len;
+
+ if (tsub->address_format == T_ATM_ENDSYS_ADDR) {
+ len = tsub->address_length;
+ ahp->ah_tstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
+
+ /* ah_tsa */
+ KM_COPY(tsub->address, cp, len);
+ cp += len;
+ } else
+ ahp->ah_tstl = 0;
+ break;
+
+ default:
+ ahp->ah_thtl = 0;
+ ahp->ah_tstl = 0;
+ }
+
+ ahp->ah_tpln = sizeof(struct in_addr);
+
+ /* ah_tpa */
+ KM_COPY((caddr_t)tip, cp, sizeof(struct in_addr));
+
+ /*
+ * Finally, send the pdu to the vcc peer
+ */
+ if (uniarp_print)
+ uniarp_pdu_print(ivp, m, "send");
+ err = atm_cm_cpcs_data(ivp->iv_arpconn, m);
+ if (err) {
+ /*
+ * Didn't make it
+ */
+ KB_FREEALL(m);
+ return (1);
+ }
+
+ return (0);
+}
+
diff --git a/sys/netatm/uni/uniarp_timer.c b/sys/netatm/uni/uniarp_timer.c
new file mode 100644
index 0000000..1f00202
--- /dev/null
+++ b/sys/netatm/uni/uniarp_timer.c
@@ -0,0 +1,320 @@
+/*
+ *
+ * ===================================
+ * 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: uniarp_timer.c,v 1.8 1998/06/29 22:44:31 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * UNI ATMARP support (RFC1577) - Timer processing
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: uniarp_timer.c,v 1.8 1998/06/29 22:44:31 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/ipatm/ipatm_var.h>
+#include <netatm/ipatm/ipatm_serv.h>
+#include <netatm/uni/unisig_var.h>
+#include <netatm/uni/uniip_var.h>
+
+
+/*
+ * Local functions
+ */
+static void uniarp_svc_oldage __P((struct uniarp *));
+static void uniarp_pvc_oldage __P((struct uniarp *));
+
+
+/*
+ * Process a UNI ATMARP entry timeout
+ *
+ * Called when a previously scheduled uniarp control block timer expires.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * tip pointer to uniarp timer control block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+uniarp_timeout(tip)
+ struct atm_time *tip;
+{
+ struct uniip *uip;
+ struct uniarp *uap;
+ struct ipvcc *ivp;
+
+
+ /*
+ * Back-off to uniarp control block
+ */
+ uap = (struct uniarp *)
+ ((caddr_t)tip - (int)(&((struct uniarp *)0)->ua_time));
+ uip = uap->ua_intf;
+
+
+ /*
+ * Do we know the IP address for this entry yet??
+ */
+ if (uap->ua_dstip.s_addr == 0) {
+
+ /*
+ * No, then send another InATMARP_REQ on each active VCC
+ * associated with this entry to solicit the peer's identity.
+ */
+ for (ivp = uap->ua_ivp; ivp; ivp = ivp->iv_arpnext) {
+ if (ivp->iv_state != IPVCC_ACTIVE)
+ continue;
+ (void) uniarp_inarp_req(uip, &uap->ua_dstatm,
+ &uap->ua_dstatmsub, ivp);
+ }
+
+ /*
+ * Restart retry timer
+ */
+ UNIARP_TIMER(uap, UNIARP_ARP_RETRY);
+ } else {
+ /*
+ * Yes, then we're trying to find the ATM address for this
+ * IP address - so send another ATMARP_REQ to the arpserver
+ * (if it's up at the moment)
+ */
+ if (uip->uip_arpstate == UIAS_CLIENT_ACTIVE)
+ (void) uniarp_arp_req(uip, &uap->ua_dstip);
+
+ /*
+ * Restart retry timer
+ */
+ UNIARP_TIMER(uap, UNIARP_ARP_RETRY);
+ }
+
+ return;
+}
+
+
+/*
+ * Process an UNI ARP SVC entry aging timer expiration
+ *
+ * This function is called when an SVC arp entry's aging timer has expired.
+ *
+ * Called at splnet().
+ *
+ * Arguments:
+ * uap pointer to atmarp table entry
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+uniarp_svc_oldage(uap)
+ struct uniarp *uap;
+{
+ struct ipvcc *ivp, *inext;
+ struct uniip *uip = uap->ua_intf;
+
+
+ /*
+ * Permanent (manually installed) entries are never aged
+ */
+ if (uap->ua_origin >= UAO_PERM)
+ return;
+
+ /*
+ * If entry is valid and we're out of retrys, tell
+ * IP/ATM that the SVCs can't be used
+ */
+ if ((uap->ua_flags & UAF_VALID) && (uap->ua_retry-- == 0)) {
+ uap->ua_flags |= UAF_LOCKED;
+ for (ivp = uap->ua_ivp; ivp; ivp = inext) {
+ inext = ivp->iv_arpnext;
+ (*ivp->iv_ipnif->inf_arpnotify)(ivp, MAP_INVALID);
+ }
+ uap->ua_flags &= ~(UAF_LOCKED | UAF_VALID);
+ uap->ua_origin = 0;
+
+ /*
+ * Delete and free an unused entry
+ */
+ if (uap->ua_ivp == NULL) {
+ UNIARP_CANCEL(uap);
+ UNIARP_DELETE(uap);
+ atm_free((caddr_t)uap);
+ return;
+ }
+ }
+
+ /*
+ * We want to try and refresh this entry but we don't want
+ * to keep unused entries laying around forever.
+ */
+ if (uap->ua_ivp || (uap->ua_flags & UAF_USED)) {
+ if (uip->uip_arpstate == UIAS_CLIENT_ACTIVE) {
+ /*
+ * If we are a client (and the server VCC is active),
+ * then we'll ask the server for a refresh
+ */
+ (void) uniarp_arp_req(uip, &uap->ua_dstip);
+ } else {
+ /*
+ * Otherwise, solicit the each active VCC peer with
+ * an Inverse ATMARP
+ */
+ for (ivp = uap->ua_ivp; ivp; ivp = ivp->iv_arpnext) {
+ if (ivp->iv_state != IPVCC_ACTIVE)
+ continue;
+ (void) uniarp_inarp_req(uip, &uap->ua_dstatm,
+ &uap->ua_dstatmsub, ivp);
+ }
+ }
+ }
+
+ /*
+ * Reset timeout
+ */
+ if (uap->ua_flags & UAF_VALID)
+ uap->ua_aging = UNIARP_RETRY_AGE;
+ else
+ uap->ua_aging = UNIARP_REVALID_AGE;
+
+ return;
+}
+
+
+/*
+ * Process an UNI ARP PVC entry aging timer expiration
+ *
+ * This function is called when a PVC arp entry's aging timer has expired.
+ *
+ * Called at splnet().
+ *
+ * Arguments:
+ * uap pointer to atmarp table entry
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+uniarp_pvc_oldage(uap)
+ struct uniarp *uap;
+{
+ struct ipvcc *ivp = uap->ua_ivp;
+
+ /*
+ * If entry is valid and we're out of retrys, tell
+ * IP/ATM that PVC can't be used
+ */
+ if ((uap->ua_flags & UAF_VALID) && (uap->ua_retry-- == 0)) {
+ (*ivp->iv_ipnif->inf_arpnotify)(ivp, MAP_INVALID);
+ uap->ua_flags &= ~UAF_VALID;
+ }
+
+ /*
+ * Solicit peer with Inverse ATMARP
+ */
+ (void) uniarp_inarp_req(uap->ua_intf, &uap->ua_dstatm,
+ &uap->ua_dstatmsub, ivp);
+
+ /*
+ * Reset timeout
+ */
+ if (uap->ua_flags & UAF_VALID)
+ uap->ua_aging = UNIARP_RETRY_AGE;
+ else
+ uap->ua_aging = UNIARP_REVALID_AGE;
+
+ return;
+}
+
+
+/*
+ * Process a UNI ARP aging timer tick
+ *
+ * This function is called every UNIARP_AGING seconds, in order to age
+ * all the arp table entries. If an entry's timer is expired, then the
+ * uniarp old-age timeout function will be called for that entry.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * tip pointer to uniarp aging timer control block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+uniarp_aging(tip)
+ struct atm_time *tip;
+{
+ struct uniarp *uap, *unext;
+ int i;
+
+
+ /*
+ * Schedule next timeout
+ */
+ atm_timeout(&uniarp_timer, UNIARP_AGING, uniarp_aging);
+
+ /*
+ * Run through arp table bumping each entry's aging timer.
+ * If an expired timer is found, process that entry.
+ */
+ for (i = 0; i < UNIARP_HASHSIZ; i++) {
+ for (uap = uniarp_arptab[i]; uap; uap = unext) {
+ unext = uap->ua_next;
+
+ if (uap->ua_aging && --uap->ua_aging == 0)
+ uniarp_svc_oldage(uap);
+ }
+ }
+
+ /*
+ * Check out PVC aging timers too
+ */
+ for (uap = uniarp_pvctab; uap; uap = unext) {
+ unext = uap->ua_next;
+
+ if (uap->ua_aging && --uap->ua_aging == 0)
+ uniarp_pvc_oldage(uap);
+ }
+
+ /*
+ * Only fully resolved SVC entries need aging, so there's no need
+ * to examine the 'no map' table
+ */
+}
+
diff --git a/sys/netatm/uni/uniarp_vcm.c b/sys/netatm/uni/uniarp_vcm.c
new file mode 100644
index 0000000..9b1f211
--- /dev/null
+++ b/sys/netatm/uni/uniarp_vcm.c
@@ -0,0 +1,708 @@
+/*
+ *
+ * ===================================
+ * 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: uniarp_vcm.c,v 1.10 1998/06/29 22:15:46 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * UNI ATMARP support (RFC1577) - Virtual Channel Management
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: uniarp_vcm.c,v 1.10 1998/06/29 22:15:46 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/ipatm/ipatm_var.h>
+#include <netatm/ipatm/ipatm_serv.h>
+#include <netatm/uni/unisig_var.h>
+#include <netatm/uni/uniip_var.h>
+
+
+/*
+ * Local variables
+ */
+static struct attr_llc uniarp_llc = {
+ T_ATM_PRESENT,
+ {
+ T_ATM_LLC_SHARING,
+ 8,
+ {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x08, 0x06}
+ }
+};
+
+static struct t_atm_cause uniarp_cause = {
+ T_ATM_ITU_CODING,
+ T_ATM_LOC_USER,
+ T_ATM_CAUSE_TEMPORARY_FAILURE,
+ {0, 0, 0, 0}
+};
+
+
+/*
+ * Process a new PVC requiring ATMARP support
+ *
+ * This function is called after IP/ATM has successfully opened a PVC which
+ * requires ATMARP support. We will send an InATMARP request over the PVC
+ * to elicit a response from the PVC's ATMARP peer informing us of its
+ * network address. This information will also be used by IP/ATM in order
+ * to complete its address-to-VC mapping table.
+ *
+ * Arguments:
+ * ivp pointer to PVC's IPVCC control block
+ *
+ * Returns:
+ * MAP_PROCEEDING - OK so far, querying for peer's mapping
+ * MAP_FAILED - error, unable to allocate resources
+ *
+ */
+int
+uniarp_pvcopen(ivp)
+ struct ipvcc *ivp;
+{
+ struct uniip *uip;
+ struct uniarp *uap;
+ int s, err;
+
+ ATM_DEBUG1("uniarp_pvcopen: ivp=0x%x\n", (int)ivp);
+
+ ivp->iv_arpent = NULL;
+
+ /*
+ * Check things out
+ */
+ if ((ivp->iv_flags & IVF_LLC) == 0)
+ return (MAP_FAILED);
+
+ /*
+ * Get uni interface
+ */
+ uip = (struct uniip *)ivp->iv_ipnif->inf_isintf;
+ if (uip == NULL)
+ return (MAP_FAILED);
+
+ /*
+ * Get an arp map entry
+ */
+ uap = (struct uniarp *)atm_allocate(&uniarp_pool);
+ if (uap == NULL)
+ return (MAP_FAILED);
+
+ /*
+ * Create our CM connection
+ */
+ err = atm_cm_addllc(&uniarp_endpt, ivp, &uniarp_llc,
+ ivp->iv_conn, &ivp->iv_arpconn);
+ if (err) {
+ /*
+ * We don't take no (or maybe) for an answer
+ */
+ if (ivp->iv_arpconn) {
+ (void) atm_cm_release(ivp->iv_arpconn, &uniarp_cause);
+ ivp->iv_arpconn = NULL;
+ }
+ atm_free((caddr_t)uap);
+ return (MAP_FAILED);
+ }
+
+ /*
+ * Get map entry set up
+ */
+ s = splnet();
+ uap->ua_dstatm.address_format = T_ATM_ABSENT;
+ uap->ua_dstatmsub.address_format = T_ATM_ABSENT;
+ uap->ua_intf = uip;
+
+ /*
+ * Put ivp on arp entry chain
+ */
+ LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
+ ivp->iv_arpent = (struct arpmap *)uap;
+
+ /*
+ * Put arp entry on pvc chain
+ */
+ LINK2TAIL(uap, struct uniarp, uniarp_pvctab, ua_next);
+
+ /*
+ * Send Inverse ATMARP request
+ */
+ (void) uniarp_inarp_req(uip, &uap->ua_dstatm, &uap->ua_dstatmsub, ivp);
+
+ /*
+ * Start resend timer
+ */
+ uap->ua_aging = UNIARP_REVALID_AGE;
+
+ (void) splx(s);
+ return (MAP_PROCEEDING);
+}
+
+
+/*
+ * Process a new outgoing SVC requiring ATMARP support
+ *
+ * This function is called by the IP/ATM module 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
+uniarp_svcout(ivp, dst)
+ struct ipvcc *ivp;
+ struct in_addr *dst;
+{
+ struct uniip *uip;
+ struct uniarp *uap;
+ int s = splnet();
+
+ ATM_DEBUG2("uniarp_svcout: ivp=0x%x,dst=0x%x\n", (int)ivp, dst->s_addr);
+
+ ivp->iv_arpent = NULL;
+
+ /*
+ * Get uni interface
+ */
+ uip = (struct uniip *)ivp->iv_ipnif->inf_isintf;
+ if (uip == NULL) {
+ (void) splx(s);
+ return (MAP_FAILED);
+ }
+
+ /*
+ * Lookup IP destination address
+ */
+ UNIARP_LOOKUP(dst->s_addr, uap);
+
+ if (uap) {
+ /*
+ * We've got an entry, verify interface
+ */
+ if (uap->ua_intf != uip) {
+ (void) splx(s);
+ return (MAP_FAILED);
+ }
+
+ /*
+ * Chain this vcc onto entry
+ */
+ LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
+ ivp->iv_arpent = (struct arpmap *)uap;
+ uap->ua_flags |= UAF_USED;
+
+ if (uap->ua_flags & UAF_VALID) {
+ /*
+ * Entry is valid, we're done
+ */
+ (void) splx(s);
+ return (MAP_VALID);
+ } else {
+ /*
+ * We're already looking for this address
+ */
+ (void) splx(s);
+ return (MAP_PROCEEDING);
+ }
+ }
+
+ /*
+ * No info in the cache. If we're the server, then
+ * we're already authoritative, so just deny request.
+ * If we're a client but the server VCC isn't open we
+ * also deny the request.
+ */
+ if (uip->uip_arpstate != UIAS_CLIENT_ACTIVE) {
+ (void) splx(s);
+ return (MAP_FAILED);
+ }
+
+ /*
+ * We're a client with an open VCC to the server, get a new arp entry
+ */
+ uap = (struct uniarp *)atm_allocate(&uniarp_pool);
+ if (uap == NULL) {
+ (void) splx(s);
+ return (MAP_FAILED);
+ }
+
+ /*
+ * Get entry set up
+ */
+ uap->ua_dstip.s_addr = dst->s_addr;
+ uap->ua_dstatm.address_format = T_ATM_ABSENT;
+ uap->ua_dstatm.address_length = 0;
+ uap->ua_dstatmsub.address_format = T_ATM_ABSENT;
+ uap->ua_dstatmsub.address_length = 0;
+ uap->ua_intf = uip;
+
+ /*
+ * Link ipvcc to arp entry for later notification
+ */
+ LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
+ ivp->iv_arpent = (struct arpmap *)uap;
+ uap->ua_flags |= UAF_USED;
+
+ /*
+ * Add arp entry to table
+ */
+ UNIARP_ADD(uap);
+
+ /*
+ * Issue arp request for this address
+ */
+ (void) uniarp_arp_req(uip, dst);
+
+ /*
+ * Start retry timer
+ */
+ UNIARP_TIMER(uap, UNIARP_ARP_RETRY);
+
+ (void) splx(s);
+ return (MAP_PROCEEDING);
+}
+
+
+/*
+ * Process a new incoming SVC requiring ATMARP support
+ *
+ * This function is called by the IP/ATM module to resolve a caller's ATM
+ * address to its IP address for an incoming call in order to allow a
+ * bi-directional flow of IP packets on the SVC. If a valid mapping is
+ * already in our cache, then we will use it. Otherwise, we have to allocate
+ * a new arp entry and wait for the SVC to become active so that we can issue
+ * an InATMARP to the peer.
+ *
+ * Arguments:
+ * ivp pointer to SVC's IPVCC control block
+ * dst pointer to caller's ATM address
+ * dstsub pointer to caller's 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
+uniarp_svcin(ivp, dst, dstsub)
+ struct ipvcc *ivp;
+ Atm_addr *dst;
+ Atm_addr *dstsub;
+{
+ struct uniip *uip;
+ struct uniarp *uap;
+ int found = 0, i, s = splnet();
+
+ ATM_DEBUG1("uniarp_svcin: ivp=0x%x\n", (int)ivp);
+
+ /*
+ * Clear ARP entry field
+ */
+ ivp->iv_arpent = NULL;
+
+ /*
+ * Check things out
+ */
+ if ((ivp->iv_flags & IVF_LLC) == 0)
+ return (MAP_FAILED);
+
+ /*
+ * Get uni interface
+ */
+ uip = (struct uniip *)ivp->iv_ipnif->inf_isintf;
+ if (uip == NULL) {
+ (void) splx(s);
+ return (MAP_FAILED);
+ }
+
+ /*
+ * Make sure we're configured as a client or server
+ */
+ if (uip->uip_arpstate == UIAS_NOTCONF) {
+ (void) splx(s);
+ return (MAP_FAILED);
+ }
+
+ /*
+ * If we know the caller's ATM address, look it up
+ */
+ uap = NULL;
+ if (dst->address_format != T_ATM_ABSENT) {
+ for (i = 0; (i < UNIARP_HASHSIZ) && (found == 0); i++) {
+ for (uap = uniarp_arptab[i]; uap; uap = uap->ua_next) {
+ if (ATM_ADDR_EQUAL(dst, &uap->ua_dstatm) &&
+ ATM_ADDR_EQUAL(dstsub, &uap->ua_dstatmsub)){
+ found = 1;
+ break;
+ }
+ }
+ }
+ if (uap == NULL) {
+ for (uap = uniarp_nomaptab; uap; uap = uap->ua_next) {
+ if (ATM_ADDR_EQUAL(dst, &uap->ua_dstatm) &&
+ ATM_ADDR_EQUAL(dstsub, &uap->ua_dstatmsub))
+ break;
+ }
+ }
+ }
+
+ if (uap) {
+ /*
+ * We've got an entry, verify interface
+ */
+ if (uap->ua_intf != uip) {
+ (void) splx(s);
+ return (MAP_FAILED);
+ }
+
+ /*
+ * Chain the vcc onto this entry
+ */
+ LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
+ ivp->iv_arpent = (struct arpmap *)uap;
+ uap->ua_flags |= UAF_USED;
+
+ if (uap->ua_flags & UAF_VALID) {
+ /*
+ * Entry is valid, we're done
+ */
+ (void) splx(s);
+ return (MAP_VALID);
+ } else {
+ /*
+ * We're already looking for this address
+ */
+ (void) splx(s);
+ return (MAP_PROCEEDING);
+ }
+ }
+
+ /*
+ * No info in the cache - get a new arp entry
+ */
+ uap = (struct uniarp *)atm_allocate(&uniarp_pool);
+ if (uap == NULL) {
+ (void) splx(s);
+ return (MAP_FAILED);
+ }
+
+ /*
+ * Get entry set up
+ */
+ ATM_ADDR_COPY(dst, &uap->ua_dstatm);
+ ATM_ADDR_COPY(dstsub, &uap->ua_dstatmsub);
+ uap->ua_intf = uip;
+
+ /*
+ * Link ipvcc to arp entry for later notification
+ */
+ LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
+ ivp->iv_arpent = (struct arpmap *)uap;
+ uap->ua_flags |= UAF_USED;
+
+ /*
+ * Add arp entry to 'nomap' table
+ */
+ LINK2TAIL(uap, struct uniarp, uniarp_nomaptab, ua_next);
+
+ (void) splx(s);
+
+ /*
+ * Now we just wait for SVC to become active
+ */
+ return (MAP_PROCEEDING);
+}
+
+
+/*
+ * Process ARP SVC activation notification
+ *
+ * This function is called by the IP/ATM module whenever 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
+uniarp_svcactive(ivp)
+ struct ipvcc *ivp;
+{
+ struct ip_nif *inp;
+ struct uniip *uip;
+ struct uniarp *uap;
+ int err, s = splnet();
+
+ ATM_DEBUG1("uniarp_svcactive: ivp=0x%x\n", (int)ivp);
+
+ inp = ivp->iv_ipnif;
+ uip = (struct uniip *)inp->inf_isintf;
+ uap = (struct uniarp *)ivp->iv_arpent;
+
+ /*
+ * First, we need to create our CM connection
+ */
+ err = atm_cm_addllc(&uniarp_endpt, ivp, &uniarp_llc,
+ ivp->iv_conn, &ivp->iv_arpconn);
+ if (err) {
+ /*
+ * We don't take no (or maybe) for an answer
+ */
+ if (ivp->iv_arpconn) {
+ (void) atm_cm_release(ivp->iv_arpconn, &uniarp_cause);
+ ivp->iv_arpconn = NULL;
+ }
+ return (err);
+ }
+
+ /*
+ * Is this the client->server vcc??
+ */
+ if (uip->uip_arpsvrvcc == ivp) {
+
+ /*
+ * Yep, go into the client registration phase
+ */
+ uip->uip_arpstate = UIAS_CLIENT_REGISTER;
+
+ /*
+ * To register ourselves, RFC1577 says we should wait
+ * around for the server to send us an InATMARP_Request.
+ * However, draft-1577+ just has us send an ATMARP_Request
+ * for our own address. To keep everyone happy, we'll go
+ * with both and see what works!
+ */
+ (void) uniarp_arp_req(uip, &(IA_SIN(inp->inf_addr)->sin_addr));
+
+ /*
+ * Start retry timer
+ */
+ UNIIP_ARP_TIMER(uip, 1 * ATM_HZ);
+
+ (void) splx(s);
+ return (0);
+ }
+
+ /*
+ * Send an InATMARP_Request on this VCC to find out/notify who's at
+ * the other end. If we're the server, this will start off the
+ * RFC1577 registration procedure. If we're a client, then this
+ * SVC is for user data and it's pretty likely that both ends are
+ * going to be sending packets. So, if we're the caller, we'll be
+ * nice and let the callee know right away who we are. If we're the
+ * callee, let's find out asap the caller's IP address.
+ */
+ (void) uniarp_inarp_req(uip, &uap->ua_dstatm, &uap->ua_dstatmsub, ivp);
+
+ /*
+ * Start retry timer if entry isn't valid yet
+ */
+ if (((uap->ua_flags & UAF_VALID) == 0) &&
+ ((uap->ua_time.ti_flag & TIF_QUEUED) == 0))
+ UNIARP_TIMER(uap, UNIARP_ARP_RETRY);
+
+ (void) splx(s);
+ return (0);
+}
+
+
+/*
+ * Process VCC close
+ *
+ * This function is called just prior to IP/ATM closing a VCC which
+ * supports ATMARP. 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
+uniarp_vcclose(ivp)
+ struct ipvcc *ivp;
+{
+ struct uniip *uip;
+ struct uniarp *uap;
+ int s;
+
+ ATM_DEBUG1("uniarp_vcclose: ivp=0x%x\n", (int)ivp);
+
+ /*
+ * Close our CM connection
+ */
+ if (ivp->iv_arpconn) {
+ (void) atm_cm_release(ivp->iv_arpconn, &uniarp_cause);
+ ivp->iv_arpconn = NULL;
+ }
+
+ /*
+ * Get atmarp entry
+ */
+ if ((uap = (struct uniarp *)ivp->iv_arpent) == NULL)
+ return;
+ uip = uap->ua_intf;
+
+ s = splnet();
+
+ /*
+ * If this is the arpserver VCC, then schedule ourselves to
+ * reopen the connection soon
+ */
+ if (uip->uip_arpsvrvcc == ivp) {
+ uip->uip_arpsvrvcc = NULL;
+ uip->uip_arpstate = UIAS_CLIENT_POPEN;
+ UNIIP_ARP_CANCEL(uip);
+ UNIIP_ARP_TIMER(uip, 5 * ATM_HZ);
+ }
+
+ /*
+ * Remove IP VCC from chain
+ */
+ UNLINK(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
+
+ /*
+ * SVCs and PVCs are handled separately
+ */
+ if (ivp->iv_flags & IVF_SVC) {
+ /*
+ * If the mapping is currently valid or in use, or if there
+ * are other VCCs still using this mapping, we're done for now
+ */
+ if ((uap->ua_flags & (UAF_VALID | UAF_LOCKED)) ||
+ (uap->ua_origin >= UAO_PERM) ||
+ (uap->ua_ivp != NULL)) {
+ (void) splx(s);
+ return;
+ }
+
+ /*
+ * Unlink the entry
+ */
+ if (uap->ua_dstip.s_addr == 0) {
+ UNLINK(uap, struct uniarp, uniarp_nomaptab, ua_next);
+ } else {
+ UNIARP_DELETE(uap);
+ }
+ } else {
+ /*
+ * Remove entry from pvc table
+ */
+ UNLINK(uap, struct uniarp, uniarp_pvctab, ua_next);
+ }
+
+ UNIARP_CANCEL(uap);
+
+ /*
+ * Finally, free the entry
+ */
+ atm_free((caddr_t)uap);
+
+ (void) splx(s);
+ return;
+}
+
+
+/*
+ * Process ATMARP VCC Connected Notification
+ *
+ * Arguments:
+ * toku owner's connection token (ipvcc protocol block)
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+uniarp_connected(toku)
+ void *toku;
+{
+
+ /*
+ * Since we only do atm_cm_addllc()'s on active connections,
+ * we should never get called here...
+ */
+ panic("uniarp_connected");
+}
+
+
+/*
+ * Process ATMARP VCC Cleared Notification
+ *
+ * Arguments:
+ * toku owner's connection token (ipvcc protocol block)
+ * cause pointer to cause code
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+uniarp_cleared(toku, cause)
+ void *toku;
+ struct t_atm_cause *cause;
+{
+ struct ipvcc *ivp = toku;
+ int s;
+
+ s = splnet();
+
+ /*
+ * We're done with VCC
+ */
+ ivp->iv_arpconn = NULL;
+
+ /*
+ * If IP is finished with VCC, then we'll free it
+ */
+ if (ivp->iv_state == IPVCC_FREE)
+ atm_free((caddr_t)ivp);
+
+ (void) splx(s);
+}
+
diff --git a/sys/netatm/uni/uniip.c b/sys/netatm/uni/uniip.c
new file mode 100644
index 0000000..0039585
--- /dev/null
+++ b/sys/netatm/uni/uniip.c
@@ -0,0 +1,252 @@
+/*
+ *
+ * ===================================
+ * 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: uniip.c,v 1.6 1998/05/18 19:18:42 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * UNI IP interface module
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: uniip.c,v 1.6 1998/05/18 19:18:42 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/ipatm/ipatm_var.h>
+#include <netatm/ipatm/ipatm_serv.h>
+#include <netatm/uni/uniip_var.h>
+
+
+/*
+ * Local functions
+ */
+static int uniip_ipact __P((struct ip_nif *));
+static int uniip_ipdact __P((struct ip_nif *));
+
+
+/*
+ * Global variables
+ */
+struct uniip *uniip_head = NULL;
+
+struct ip_serv uniip_ipserv = {
+ uniip_ipact,
+ uniip_ipdact,
+ uniarp_ioctl,
+ uniarp_pvcopen,
+ uniarp_svcout,
+ uniarp_svcin,
+ uniarp_svcactive,
+ uniarp_vcclose,
+ NULL,
+ {ATM_AAL5, ATM_ENC_LLC},
+};
+
+
+/*
+ * Local variables
+ */
+static struct sp_info uniip_pool = {
+ "uni ip pool", /* si_name */
+ sizeof(struct uniip), /* si_blksiz */
+ 2, /* si_blkcnt */
+ 100 /* si_maxallow */
+};
+
+
+/*
+ * Process module loading notification
+ *
+ * Called whenever the uni module is initializing.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 initialization successful
+ * errno initialization failed - reason indicated
+ *
+ */
+int
+uniip_start()
+{
+ int err;
+
+ /*
+ * Tell arp to initialize stuff
+ */
+ err = uniarp_start();
+
+ return (err);
+}
+
+
+/*
+ * Process module unloading notification
+ *
+ * Called whenever the uni module is about to be unloaded. All signalling
+ * instances will have been previously detached. All uniip resources
+ * must be freed now.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 shutdown was successful
+ * errno shutdown failed - reason indicated
+ *
+ */
+int
+uniip_stop()
+{
+
+ /*
+ * All IP interfaces should be gone
+ */
+ if (uniip_head)
+ return (EBUSY);
+
+ /*
+ * Tell arp to stop
+ */
+ uniarp_stop();
+
+ /*
+ * Free our storage pools
+ */
+ atm_release_pool(&uniip_pool);
+
+ return (0);
+}
+
+
+/*
+ * 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
+uniip_ipact(inp)
+ struct ip_nif *inp;
+{
+ struct uniip *uip;
+
+ /*
+ * Make sure we don't already have this interface
+ */
+ for (uip = uniip_head; uip; uip = uip->uip_next) {
+ if (uip->uip_ipnif == inp)
+ return (EEXIST);
+ }
+
+ /*
+ * Get a new interface control block
+ */
+ uip = (struct uniip *)atm_allocate(&uniip_pool);
+ if (uip == NULL)
+ return (ENOMEM);
+
+ /*
+ * Initialize and link up
+ */
+ uip->uip_ipnif = inp;
+ LINK2TAIL(uip, struct uniip, uniip_head, uip_next);
+
+ /*
+ * Link from IP world
+ */
+ inp->inf_isintf = (caddr_t)uip;
+
+ /*
+ * Tell arp about new interface
+ */
+ uniarp_ipact(uip);
+
+ 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
+uniip_ipdact(inp)
+ struct ip_nif *inp;
+{
+ struct uniip *uip;
+
+ /*
+ * Get the appropriate IP interface block
+ */
+ uip = (struct uniip *)inp->inf_isintf;
+ if (uip == NULL)
+ return (ENXIO);
+
+ /*
+ * Let arp know about this
+ */
+ uniarp_ipdact(uip);
+
+ /*
+ * Free interface info
+ */
+ UNLINK(uip, struct uniip, uniip_head, uip_next);
+ if (uip->uip_prefix != NULL)
+ KM_FREE(uip->uip_prefix,
+ uip->uip_nprefix * sizeof(struct uniarp_prf), M_DEVBUF);
+ atm_free((caddr_t)uip);
+
+ return (0);
+}
+
diff --git a/sys/netatm/uni/uniip_var.h b/sys/netatm/uni/uniip_var.h
new file mode 100644
index 0000000..ea1eb8c
--- /dev/null
+++ b/sys/netatm/uni/uniip_var.h
@@ -0,0 +1,318 @@
+/*
+ *
+ * ===================================
+ * 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: uniip_var.h,v 1.9 1998/07/13 00:00:39 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI Support
+ * ---------------------
+ *
+ * IP interface control blocks
+ *
+ */
+
+#ifndef _UNI_UNIIP_VAR_H
+#define _UNI_UNIIP_VAR_H
+
+#ifdef ATM_KERNEL
+/*
+ * UNI IP network interface structure. There will be one such structure for
+ * each IP network interface attached via a UNI signalling instance.
+ */
+struct uniip {
+ struct uniip *uip_next; /* Next attached IP interface */
+ struct ip_nif *uip_ipnif; /* IP network interface */
+ u_char uip_flags; /* Interface flags (see below) */
+
+ /* ATMARP (RFC1577) */
+ u_char uip_arpstate; /* ARP interface state (see below) */
+ struct arpmap uip_arpsvrmap; /* ATMARP server map info */
+ struct ipvcc *uip_arpsvrvcc; /* ATMARP server's VCC */
+ int uip_nprefix; /* Count of IP prefixes (server only) */
+ struct uniarp_prf *uip_prefix; /* Array of IP prefixes (server only) */
+ struct atm_time uip_arptime; /* ARP timer controls */
+};
+#define uip_arpsvrip uip_arpsvrmap.am_dstip
+#define uip_arpsvratm uip_arpsvrmap.am_dstatm
+#define uip_arpsvrsub uip_arpsvrmap.am_dstatmsub
+#endif /* ATM_KERNEL */
+
+/*
+ * UNI Interface Flags
+ */
+#define UIF_IFADDR 0x01 /* Interface address is set */
+
+/*
+ * UNI ARP Interface States
+ */
+#define UIAS_NOTCONF 1 /* Not configured */
+#define UIAS_SERVER_ACTIVE 2 /* Server - active */
+#define UIAS_CLIENT_PADDR 3 /* Client - pending ATM address */
+#define UIAS_CLIENT_POPEN 4 /* Client - pending server vcc open */
+#define UIAS_CLIENT_REGISTER 5 /* Client - registering with server */
+#define UIAS_CLIENT_ACTIVE 6 /* Client - active */
+
+
+#ifdef ATM_KERNEL
+/*
+ * Structure for allowable IP prefixes for ATMARP server registration
+ */
+struct uniarp_prf {
+ struct in_addr upf_addr; /* Prefix address */
+ struct in_addr upf_mask; /* Prefix mask */
+};
+
+
+/*
+ * UNI ARP protocol constants
+ */
+#define UNIARP_AGING (60 * ATM_HZ) /* Aging timer tick */
+#define UNIARP_HASHSIZ 19 /* Hash table size */
+#define UNIARP_REGIS_REFRESH (15 * 60 * ATM_HZ)
+ /* Client registration refresh timer */
+#define UNIARP_REGIS_RETRY (60 * ATM_HZ)
+ /* Client registration retry timer */
+#define UNIARP_ARP_RETRY (3 * ATM_HZ) /* ARP command retry timer */
+#define UNIARP_CLIENT_AGE 12 /* Client validation timeout */
+#define UNIARP_CLIENT_RETRY 3 /* Client validation retrys */
+#define UNIARP_SERVER_AGE 17 /* Server validation timeout */
+#define UNIARP_SERVER_RETRY 3 /* Server validation retrys */
+#define UNIARP_RETRY_AGE 1 /* Retry timeout */
+#define UNIARP_REVALID_AGE 2 /* Revalidation timeout */
+#define UNIARP_MIN_REFRESH 10 /* Minimum entry refresh time */
+
+
+/*
+ * Structure for ATMARP mappings. Each of these structures will contain
+ * IP address to ATM hardware address mappings. There will be one such
+ * structure for each IP address and for each unresolved ATM address
+ * currently in use.
+ */
+struct uniarp {
+ struct arpmap ua_arpmap; /* Common entry header */
+ struct uniip *ua_intf; /* Interface where we learned answer */
+ struct uniarp *ua_next; /* Hash chain link */
+ u_char ua_flags; /* Flags (see below) */
+ u_char ua_origin; /* Source of mapping (see below) */
+ u_char ua_retry; /* Retry counter */
+ u_char ua_aging; /* Aging timeout value (minutes) */
+ struct ipvcc *ua_ivp; /* Head of IP VCC chain */
+ struct atm_time ua_time; /* Timer controls */
+};
+#define ua_dstip ua_arpmap.am_dstip
+#define ua_dstatm ua_arpmap.am_dstatm
+#define ua_dstatmsub ua_arpmap.am_dstatmsub
+#endif /* ATM_KERNEL */
+
+/*
+ * UNIARP Entry Flags
+ */
+#define UAF_VALID ARPF_VALID /* Entry is valid */
+#define UAF_REFRESH ARPF_REFRESH /* Entry has been refreshed */
+#define UAF_LOCKED 0x04 /* Entry is locked */
+#define UAF_USED 0x08 /* Entry has been used recently */
+
+/*
+ * UNIARP Entry Origin
+ *
+ * The origin values are ranked according to the source precedence.
+ * Larger values are more preferred.
+ */
+#define UAO_LOCAL 100 /* Local address */
+#define UAO_PERM ARP_ORIG_PERM /* Permanently installed */
+#define UAO_REGISTER 40 /* Learned via client registration */
+#define UAO_SCSP 30 /* Learned via SCSP */
+#define UAO_LOOKUP 20 /* Learned via server lookup */
+#define UAO_PEER_RSP 15 /* Learned from peer - inarp rsp */
+#define UAO_PEER_REQ 10 /* Learned from peer - inarp req */
+
+/*
+ * ATMARP/InATMARP Packet Format
+ */
+struct atmarp_hdr {
+ u_short ah_hrd; /* Hardware type (see below) */
+ u_short ah_pro; /* Protocol type */
+ u_char ah_shtl; /* Type/len of source ATM address */
+ u_char ah_sstl; /* Type/len of source ATM subaddress */
+ u_short ah_op; /* Operation code (see below) */
+ u_char ah_spln; /* Length of source protocol address */
+ u_char ah_thtl; /* Type/len of target ATM address */
+ u_char ah_tstl; /* Type/len of target ATM subaddress */
+ u_char ah_tpln; /* Length of target protocol address */
+#ifdef notdef
+ /* Variable size fields */
+ u_char ah_sha[]; /* Source ATM address */
+ u_char ah_ssa[]; /* Source ATM subaddress */
+ u_char ah_spa[]; /* Source protocol address */
+ u_char ah_tha[]; /* Target ATM subaddress */
+ u_char ah_tsa[]; /* Target ATM address */
+ u_char ah_tpa[]; /* Target protocol subaddress */
+#endif
+};
+
+/*
+ * Hardware types
+ */
+#define ARP_ATMFORUM 19
+
+/*
+ * Operation types
+ */
+#define ARP_REQUEST 1 /* ATMARP request */
+#define ARP_REPLY 2 /* ATMARP response */
+#define INARP_REQUEST 8 /* InATMARP request */
+#define INARP_REPLY 9 /* InATMARP response */
+#define ARP_NAK 10 /* ATMARP negative ack */
+
+/*
+ * Type/length fields
+ */
+#define ARP_TL_TMASK 0x40 /* Type mask */
+#define ARP_TL_NSAPA 0x00 /* Type = ATM Forum NSAPA */
+#define ARP_TL_E164 0x40 /* Type = E.164 */
+#define ARP_TL_LMASK 0x3f /* Length mask */
+
+
+#ifdef ATM_KERNEL
+/*
+ * Timer macros
+ */
+#define UNIIP_ARP_TIMER(s, t) atm_timeout(&(s)->uip_arptime, (t), uniarp_iftimeout)
+#define UNIIP_ARP_CANCEL(s) atm_untimeout(&(s)->uip_arptime)
+#define UNIARP_TIMER(s, t) atm_timeout(&(s)->ua_time, (t), uniarp_timeout)
+#define UNIARP_CANCEL(s) atm_untimeout(&(s)->ua_time)
+
+
+/*
+ * Macros for manipulating UNIARP tables and entries
+ */
+#define UNIARP_HASH(ip) ((u_long)(ip) % UNIARP_HASHSIZ)
+
+#define UNIARP_ADD(ua) \
+{ \
+ struct uniarp **h; \
+ h = &uniarp_arptab[UNIARP_HASH((ua)->ua_dstip.s_addr)]; \
+ LINK2TAIL((ua), struct uniarp, *h, ua_next); \
+}
+
+#define UNIARP_DELETE(ua) \
+{ \
+ struct uniarp **h; \
+ h = &uniarp_arptab[UNIARP_HASH((ua)->ua_dstip.s_addr)]; \
+ UNLINK((ua), struct uniarp, *h, ua_next); \
+}
+
+#define UNIARP_LOOKUP(ip, ua) \
+{ \
+ for ((ua) = uniarp_arptab[UNIARP_HASH(ip)]; \
+ (ua); (ua) = (ua)->ua_next) { \
+ if ((ua)->ua_dstip.s_addr == (ip)) \
+ break; \
+ } \
+}
+
+
+/*
+ * Global UNIARP Statistics
+ */
+struct uniarp_stat {
+ u_long uas_rcvdrop; /* Input packets dropped */
+};
+
+
+/*
+ * External variables
+ */
+extern struct uniip *uniip_head;
+extern struct ip_serv uniip_ipserv;
+extern struct uniarp *uniarp_arptab[];
+extern struct uniarp *uniarp_nomaptab;
+extern struct uniarp *uniarp_pvctab;
+extern struct sp_info uniarp_pool;
+extern struct atm_time uniarp_timer;
+extern int uniarp_print;
+extern Atm_endpoint uniarp_endpt;
+extern struct uniarp_stat uniarp_stat;
+
+
+/*
+ * Global function declarations
+ */
+ /* uniarp.c */
+int uniarp_start __P((void));
+void uniarp_stop __P((void));
+void uniarp_ipact __P((struct uniip *));
+void uniarp_ipdact __P((struct uniip *));
+void uniarp_ifaddr __P((struct siginst *));
+void uniarp_iftimeout __P((struct atm_time *));
+int uniarp_ioctl __P((int, caddr_t, caddr_t));
+caddr_t uniarp_getname __P((void *));
+
+ /* uniarp_cache.c */
+int uniarp_cache_svc __P((struct uniip *, struct in_addr *,
+ Atm_addr *, Atm_addr *, u_int));
+void uniarp_cache_pvc __P((struct ipvcc *, struct in_addr *,
+ Atm_addr *, Atm_addr *));
+int uniarp_validate_ip __P((struct uniip *, struct in_addr *,
+ u_int));
+
+ /* uniarp_input.c */
+void uniarp_cpcs_data __P((void *, KBuffer *));
+void uniarp_pdu_print __P((struct ipvcc *, KBuffer *, char *));
+
+ /* uniarp_output.c */
+int uniarp_arp_req __P((struct uniip *, struct in_addr *));
+int uniarp_arp_rsp __P((struct uniip *, struct arpmap *,
+ struct in_addr *, Atm_addr *,
+ Atm_addr *, struct ipvcc *));
+int uniarp_arp_nak __P((struct uniip *, KBuffer *, struct ipvcc *));
+int uniarp_inarp_req __P((struct uniip *, Atm_addr *,
+ Atm_addr *, struct ipvcc *));
+int uniarp_inarp_rsp __P((struct uniip *, struct in_addr *,
+ Atm_addr *, Atm_addr *, struct ipvcc *));
+
+ /* uniarp_timer.c */
+void uniarp_timeout __P((struct atm_time *));
+void uniarp_aging __P((struct atm_time *));
+
+ /* uniarp_vcm.c */
+int uniarp_pvcopen __P((struct ipvcc *));
+int uniarp_svcout __P((struct ipvcc *, struct in_addr *));
+int uniarp_svcin __P((struct ipvcc *, Atm_addr *, Atm_addr *));
+int uniarp_svcactive __P((struct ipvcc *));
+void uniarp_vcclose __P((struct ipvcc *));
+void uniarp_connected __P((void *));
+void uniarp_cleared __P((void *, struct t_atm_cause *));
+
+ /* uniip.c */
+int uniip_start __P((void));
+int uniip_stop __P((void));
+
+
+#endif /* ATM_KERNEL */
+
+#endif /* _UNI_UNIIP_VAR_H */
diff --git a/sys/netatm/uni/unisig.h b/sys/netatm/uni/unisig.h
new file mode 100644
index 0000000..b69714d
--- /dev/null
+++ b/sys/netatm/uni/unisig.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * ===================================
+ * 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: unisig.h,v 1.2 1997/05/06 22:21:33 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI 3.0/3.1 Signalling Manager
+ * ----------------------------------------
+ *
+ * Protocol control blocks
+ *
+ */
+
+#ifndef _UNISIG_H
+#define _UNISIG_H
+
+/*
+ * ATM Forum UNI 3.0/3.1 Signalling
+ */
+#define UNISIG_SIG_VPI 0 /* Signalling VPI */
+#define UNISIG_SIG_VCI 5 /* Signalling VCI */
+
+#define STACK_SSCF "uni_sscf"
+
+#endif /* _UNISIG_H */
diff --git a/sys/netatm/uni/unisig_decode.c b/sys/netatm/uni/unisig_decode.c
new file mode 100644
index 0000000..98f5dfd
--- /dev/null
+++ b/sys/netatm/uni/unisig_decode.c
@@ -0,0 +1,2474 @@
+/*
+ *
+ * ===================================
+ * 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: unisig_decode.c,v 1.13 1998/08/26 23:29:20 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI 3.0/3.1 Signalling Manager
+ * ----------------------------------------
+ *
+ * Message formatting module
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: unisig_decode.c,v 1.13 1998/08/26 23:29:20 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/unisig.h>
+#include <netatm/uni/unisig_var.h>
+#include <netatm/uni/unisig_msg.h>
+#include <netatm/uni/unisig_mbuf.h>
+#include <netatm/uni/unisig_decode.h>
+
+#define ALLOC_IE(ie) \
+ (ie) = (struct ie_generic *) atm_allocate(&unisig_iepool); \
+ if (!ie) \
+ return(ENOMEM);
+
+
+/*
+ * Local functions
+ */
+static int usf_dec_ie __P((struct usfmt *, struct unisig_msg *, struct ie_generic *));
+static int usf_dec_ie_hdr __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_aalp __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_clrt __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_bbcp __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_bhli __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_blli __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_clst __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_cdad __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_cdsa __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_cgad __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_cgsa __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_caus __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_cnid __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_qosp __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_brpi __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_rsti __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_bsdc __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_trnt __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_uimp __P((struct usfmt *, struct ie_generic *));
+static int usf_dec_ie_ident __P((struct usfmt *, struct ie_generic *,
+ struct ie_decode_tbl *));
+static int usf_dec_atm_addr __P((struct usfmt *, Atm_addr *, int));
+
+
+/*
+ * Table associating IE type with IE vector index
+ */
+u_char unisig_ie_ident_vec[] = {
+ UNI_IE_AALP,
+ UNI_IE_CLRT,
+ UNI_IE_BBCP,
+ UNI_IE_BHLI,
+ UNI_IE_BLLI,
+ UNI_IE_CLST,
+ UNI_IE_CDAD,
+ UNI_IE_CDSA,
+ UNI_IE_CGAD,
+ UNI_IE_CGSA,
+ UNI_IE_CAUS,
+ UNI_IE_CNID,
+ UNI_IE_QOSP,
+ UNI_IE_BRPI,
+ UNI_IE_RSTI,
+ UNI_IE_BLSH,
+ UNI_IE_BNSH,
+ UNI_IE_BSDC,
+ UNI_IE_TRNT,
+ UNI_IE_EPRF,
+ UNI_IE_EPST
+};
+
+
+/*
+ * Tables specifying which IEs are mandatory, optional, and
+ * not allowed for each Q.2931 message type
+ */
+static u_char uni_calp_ie_tbl[] = {
+ IE_NA, /* ATM AAL Parameters */
+ IE_NA, /* ATM User Cell Rate */
+ IE_NA, /* Broadband Bearer Capability */
+ IE_NA, /* Broadband High Layer Information */
+ IE_NA, /* Broadband Low Layer Information */
+ IE_NA, /* Call State */
+ IE_NA, /* Called Party Number */
+ IE_NA, /* Called Party Subaddress */
+ IE_NA, /* Calling Party Number */
+ IE_NA, /* Calling Party Subaddress */
+ IE_NA, /* Cause */
+ IE_OPT, /* Connection Identifier */
+ IE_NA, /* Quality of Service Parameters */
+ IE_NA, /* Broadband Repeat Indicator */
+ IE_NA, /* Restart Indicator */
+ IE_NA, /* Broadband Locking Shift */
+ IE_NA, /* Broadband Non-locking Shift */
+ IE_NA, /* Broadband Sending Complete */
+ IE_NA, /* Transit Net */
+ IE_OPT, /* Endpoint Reference */
+ IE_NA /* Endpoint State */
+};
+
+static u_char uni_conn_ie_tbl[] = {
+ IE_OPT, /* ATM AAL Parameters */
+ IE_NA, /* ATM User Cell Rate */
+ IE_NA, /* Broadband Bearer Capability */
+ IE_NA, /* Broadband High Layer Information */
+ IE_OPT, /* Broadband Low Layer Information */
+ IE_NA, /* Call State */
+ IE_NA, /* Called Party Number */
+ IE_NA, /* Called Party Subaddress */
+ IE_NA, /* Calling Party Number */
+ IE_NA, /* Calling Party Subaddress */
+ IE_NA, /* Cause */
+ IE_OPT, /* Connection Identifier */
+ IE_NA, /* Quality of Service Parameters */
+ IE_NA, /* Broadband Repeat Indicator */
+ IE_NA, /* Restart Indicator */
+ IE_NA, /* Broadband Locking Shift */
+ IE_NA, /* Broadband Non-locking Shift */
+ IE_NA, /* Broadband Sending Complete */
+ IE_NA, /* Transit Net */
+ IE_OPT, /* Endpoint Reference */
+ IE_NA /* Endpoint State */
+};
+
+static u_char uni_cack_ie_tbl[] = {
+ IE_NA, /* ATM AAL Parameters */
+ IE_NA, /* ATM User Cell Rate */
+ IE_NA, /* Broadband Bearer Capability */
+ IE_NA, /* Broadband High Layer Information */
+ IE_NA, /* Broadband Low Layer Information */
+ IE_NA, /* Call State */
+ IE_NA, /* Called Party Number */
+ IE_NA, /* Called Party Subaddress */
+ IE_NA, /* Calling Party Number */
+ IE_NA, /* Calling Party Subaddress */
+ IE_NA, /* Cause */
+ IE_NA, /* Connection Identifier */
+ IE_NA, /* Quality of Service Parameters */
+ IE_NA, /* Broadband Repeat Indicator */
+ IE_NA, /* Restart Indicator */
+ IE_NA, /* Broadband Locking Shift */
+ IE_NA, /* Broadband Non-locking Shift */
+ IE_NA, /* Broadband Sending Complete */
+ IE_NA, /* Transit Net */
+ IE_NA, /* Endpoint Reference */
+ IE_NA /* Endpoint State */
+};
+
+static u_char uni_setu_ie_tbl[] = {
+ IE_MAND, /* ATM AAL Parameters (not required by
+ UNI 3.0) */
+ IE_MAND, /* ATM User Cell Rate */
+ IE_MAND, /* Broadband Bearer Capability */
+ IE_OPT, /* Broadband High Layer Information */
+ IE_MAND, /* Broadband Low Layer Information (not required by UNI 3.0 */
+ IE_NA, /* Call State */
+ IE_MAND, /* Called Party Number */
+ IE_OPT, /* Called Party Subaddress */
+ IE_OPT, /* Calling Party Number */
+ IE_OPT, /* Calling Party Subaddress */
+ IE_NA, /* Cause */
+ IE_MAND, /* Connection Identifier */
+ IE_MAND, /* Quality of Service Parameters */
+ IE_OPT, /* Broadband Repeat Indicator */
+ IE_NA, /* Restart Indicator */
+ IE_NA, /* Broadband Locking Shift */
+ IE_NA, /* Broadband Non-locking Shift */
+ IE_OPT, /* Broadband Sending Complete */
+ IE_NA, /* Transit Net */
+ IE_OPT, /* Endpoint Reference */
+ IE_NA /* Endpoint State */
+};
+
+static u_char uni_rlse_ie_tbl[] = {
+ IE_NA, /* ATM AAL Parameters */
+ IE_NA, /* ATM User Cell Rate */
+ IE_NA, /* Broadband Bearer Capability */
+ IE_NA, /* Broadband High Layer Information */
+ IE_NA, /* Broadband Low Layer Information */
+ IE_NA, /* Call State */
+ IE_NA, /* Called Party Number */
+ IE_NA, /* Called Party Subaddress */
+ IE_NA, /* Calling Party Number */
+ IE_NA, /* Calling Party Subaddress */
+ IE_MAND, /* Cause */
+ IE_NA, /* Connection Identifier */
+ IE_NA, /* Quality of Service Parameters */
+ IE_NA, /* Broadband Repeat Indicator */
+ IE_NA, /* Restart Indicator */
+ IE_NA, /* Broadband Locking Shift */
+ IE_NA, /* Broadband Non-locking Shift */
+ IE_NA, /* Broadband Sending Complete */
+ IE_NA, /* Transit Net */
+ IE_NA, /* Endpoint Reference */
+ IE_NA /* Endpoint State */
+};
+
+static u_char uni_rlsc_ie_tbl[] = {
+ IE_NA, /* ATM AAL Parameters */
+ IE_NA, /* ATM User Cell Rate */
+ IE_NA, /* Broadband Bearer Capability */
+ IE_NA, /* Broadband High Layer Information */
+ IE_NA, /* Broadband Low Layer Information */
+ IE_NA, /* Call State */
+ IE_NA, /* Called Party Number */
+ IE_NA, /* Called Party Subaddress */
+ IE_NA, /* Calling Party Number */
+ IE_NA, /* Calling Party Subaddress */
+ IE_MAND, /* Cause */
+ IE_NA, /* Connection Identifier */
+ IE_NA, /* Quality of Service Parameters */
+ IE_NA, /* Broadband Repeat Indicator */
+ IE_NA, /* Restart Indicator */
+ IE_NA, /* Broadband Locking Shift */
+ IE_NA, /* Broadband Non-locking Shift */
+ IE_NA, /* Broadband Sending Complete */
+ IE_NA, /* Transit Net */
+ IE_NA, /* Endpoint Reference */
+ IE_NA /* Endpoint State */
+};
+
+static u_char uni_rstr_ie_tbl[] = {
+ IE_NA, /* ATM AAL Parameters */
+ IE_NA, /* ATM User Cell Rate */
+ IE_NA, /* Broadband Bearer Capability */
+ IE_NA, /* Broadband High Layer Information */
+ IE_NA, /* Broadband Low Layer Information */
+ IE_NA, /* Call State */
+ IE_NA, /* Called Party Number */
+ IE_NA, /* Called Party Subaddress */
+ IE_NA, /* Calling Party Number */
+ IE_NA, /* Calling Party Subaddress */
+ IE_NA, /* Cause */
+ IE_OPT, /* Connection Identifier */
+ IE_NA, /* Quality of Service Parameters */
+ IE_NA, /* Broadband Repeat Indicator */
+ IE_MAND, /* Restart Indicator */
+ IE_NA, /* Broadband Locking Shift */
+ IE_NA, /* Broadband Non-locking Shift */
+ IE_NA, /* Broadband Sending Complete */
+ IE_NA, /* Transit Net */
+ IE_NA, /* Endpoint Reference */
+ IE_NA /* Endpoint State */
+};
+
+static u_char uni_rsta_ie_tbl[] = {
+ IE_NA, /* ATM AAL Parameters */
+ IE_NA, /* ATM User Cell Rate */
+ IE_NA, /* Broadband Bearer Capability */
+ IE_NA, /* Broadband High Layer Information */
+ IE_NA, /* Broadband Low Layer Information */
+ IE_NA, /* Call State */
+ IE_NA, /* Called Party Number */
+ IE_NA, /* Called Party Subaddress */
+ IE_NA, /* Calling Party Number */
+ IE_NA, /* Calling Party Subaddress */
+ IE_NA, /* Cause */
+ IE_OPT, /* Connection Identifier */
+ IE_NA, /* Quality of Service Parameters */
+ IE_NA, /* Broadband Repeat Indicator */
+ IE_MAND, /* Restart Indicator */
+ IE_NA, /* Broadband Locking Shift */
+ IE_NA, /* Broadband Non-locking Shift */
+ IE_NA, /* Broadband Sending Complete */
+ IE_NA, /* Transit Net */
+ IE_NA, /* Endpoint Reference */
+ IE_NA /* Endpoint State */
+};
+
+static u_char uni_stat_ie_tbl[] = {
+ IE_NA, /* ATM AAL Parameters */
+ IE_NA, /* ATM User Cell Rate */
+ IE_NA, /* Broadband Bearer Capability */
+ IE_NA, /* Broadband High Layer Information */
+ IE_NA, /* Broadband Low Layer Information */
+ IE_MAND, /* Call State */
+ IE_NA, /* Called Party Number */
+ IE_NA, /* Called Party Subaddress */
+ IE_NA, /* Calling Party Number */
+ IE_NA, /* Calling Party Subaddress */
+ IE_MAND, /* Cause */
+ IE_NA, /* Connection Identifier */
+ IE_NA, /* Quality of Service Parameters */
+ IE_NA, /* Broadband Repeat Indicator */
+ IE_NA, /* Restart Indicator */
+ IE_NA, /* Broadband Locking Shift */
+ IE_NA, /* Broadband Non-locking Shift */
+ IE_NA, /* Broadband Sending Complete */
+ IE_NA, /* Transit Net */
+ IE_OPT, /* Endpoint Reference */
+ IE_OPT /* Endpoint State */
+};
+
+static u_char uni_senq_ie_tbl[] = {
+ IE_NA, /* ATM AAL Parameters */
+ IE_NA, /* ATM User Cell Rate */
+ IE_NA, /* Broadband Bearer Capability */
+ IE_NA, /* Broadband High Layer Information */
+ IE_NA, /* Broadband Low Layer Information */
+ IE_NA, /* Call State */
+ IE_NA, /* Called Party Number */
+ IE_NA, /* Called Party Subaddress */
+ IE_NA, /* Calling Party Number */
+ IE_NA, /* Calling Party Subaddress */
+ IE_NA, /* Cause */
+ IE_NA, /* Connection Identifier */
+ IE_NA, /* Quality of Service Parameters */
+ IE_NA, /* Broadband Repeat Indicator */
+ IE_NA, /* Restart Indicator */
+ IE_NA, /* Broadband Locking Shift */
+ IE_NA, /* Broadband Non-locking Shift */
+ IE_NA, /* Broadband Sending Complete */
+ IE_NA, /* Transit Net */
+ IE_OPT, /* Endpoint Reference */
+ IE_NA /* Endpoint State */
+};
+
+static u_char uni_addp_ie_tbl[] = {
+ IE_OPT, /* ATM AAL Parameters */
+ IE_NA, /* ATM User Cell Rate */
+ IE_NA, /* Broadband Bearer Capability */
+ IE_OPT, /* Broadband High Layer Information */
+ IE_OPT, /* Broadband Low Layer Information */
+ IE_NA, /* Call State */
+ IE_MAND, /* Called Party Number */
+ IE_OPT, /* Called Party Subaddress */
+ IE_OPT, /* Calling Party Number */
+ IE_OPT, /* Calling Party Subaddress */
+ IE_NA, /* Cause */
+ IE_NA, /* Connection Identifier */
+ IE_NA, /* Quality of Service Parameters */
+ IE_NA, /* Broadband Repeat Indicator */
+ IE_NA, /* Restart Indicator */
+ IE_NA, /* Broadband Locking Shift */
+ IE_NA, /* Broadband Non-locking Shift */
+ IE_OPT, /* Broadband Sending Complete */
+ IE_NA, /* Transit Net */
+ IE_MAND, /* Endpoint Reference */
+ IE_NA /* Endpoint State */
+};
+
+static u_char uni_adpa_ie_tbl[] = {
+ IE_NA, /* ATM AAL Parameters */
+ IE_NA, /* ATM User Cell Rate */
+ IE_NA, /* Broadband Bearer Capability */
+ IE_NA, /* Broadband High Layer Information */
+ IE_NA, /* Broadband Low Layer Information */
+ IE_NA, /* Call State */
+ IE_NA, /* Called Party Number */
+ IE_NA, /* Called Party Subaddress */
+ IE_NA, /* Calling Party Number */
+ IE_NA, /* Calling Party Subaddress */
+ IE_NA, /* Cause */
+ IE_NA, /* Connection Identifier */
+ IE_NA, /* Quality of Service Parameters */
+ IE_NA, /* Broadband Repeat Indicator */
+ IE_NA, /* Restart Indicator */
+ IE_NA, /* Broadband Locking Shift */
+ IE_NA, /* Broadband Non-locking Shift */
+ IE_NA, /* Broadband Sending Complete */
+ IE_NA, /* Transit Net */
+ IE_MAND, /* Endpoint Reference */
+ IE_NA /* Endpoint State */
+};
+
+static u_char uni_adpr_ie_tbl[] = {
+ IE_NA, /* ATM AAL Parameters */
+ IE_NA, /* ATM User Cell Rate */
+ IE_NA, /* Broadband Bearer Capability */
+ IE_NA, /* Broadband High Layer Information */
+ IE_NA, /* Broadband Low Layer Information */
+ IE_NA, /* Call State */
+ IE_NA, /* Called Party Number */
+ IE_NA, /* Called Party Subaddress */
+ IE_NA, /* Calling Party Number */
+ IE_NA, /* Calling Party Subaddress */
+ IE_MAND, /* Cause */
+ IE_NA, /* Connection Identifier */
+ IE_NA, /* Quality of Service Parameters */
+ IE_NA, /* Broadband Repeat Indicator */
+ IE_NA, /* Restart Indicator */
+ IE_NA, /* Broadband Locking Shift */
+ IE_NA, /* Broadband Non-locking Shift */
+ IE_NA, /* Broadband Sending Complete */
+ IE_NA, /* Transit Net */
+ IE_MAND, /* Endpoint Reference */
+ IE_NA /* Endpoint State */
+};
+
+static u_char uni_drpp_ie_tbl[] = {
+ IE_NA, /* ATM AAL Parameters */
+ IE_NA, /* ATM User Cell Rate */
+ IE_NA, /* Broadband Bearer Capability */
+ IE_NA, /* Broadband High Layer Information */
+ IE_NA, /* Broadband Low Layer Information */
+ IE_NA, /* Call State */
+ IE_NA, /* Called Party Number */
+ IE_NA, /* Called Party Subaddress */
+ IE_NA, /* Calling Party Number */
+ IE_NA, /* Calling Party Subaddress */
+ IE_MAND, /* Cause */
+ IE_NA, /* Connection Identifier */
+ IE_NA, /* Quality of Service Parameters */
+ IE_NA, /* Broadband Repeat Indicator */
+ IE_NA, /* Restart Indicator */
+ IE_NA, /* Broadband Locking Shift */
+ IE_NA, /* Broadband Non-locking Shift */
+ IE_NA, /* Broadband Sending Complete */
+ IE_NA, /* Transit Net */
+ IE_MAND, /* Endpoint Reference */
+ IE_NA /* Endpoint State */
+};
+
+static u_char uni_drpa_ie_tbl[] = {
+ IE_NA, /* ATM AAL Parameters */
+ IE_NA, /* ATM User Cell Rate */
+ IE_NA, /* Broadband Bearer Capability */
+ IE_NA, /* Broadband High Layer Information */
+ IE_NA, /* Broadband Low Layer Information */
+ IE_NA, /* Call State */
+ IE_NA, /* Called Party Number */
+ IE_NA, /* Called Party Subaddress */
+ IE_NA, /* Calling Party Number */
+ IE_NA, /* Calling Party Subaddress */
+ IE_OPT, /* Cause */
+ IE_NA, /* Connection Identifier */
+ IE_NA, /* Quality of Service Parameters */
+ IE_NA, /* Broadband Repeat Indicator */
+ IE_NA, /* Restart Indicator */
+ IE_NA, /* Broadband Locking Shift */
+ IE_NA, /* Broadband Non-locking Shift */
+ IE_NA, /* Broadband Sending Complete */
+ IE_NA, /* Transit Net */
+ IE_MAND, /* Endpoint Reference */
+ IE_NA /* Endpoint State */
+};
+
+/*
+ * Table of Q.2931 message types
+ */
+static struct {
+ u_char msg_type;
+ u_char *msg_ie_tbl;
+} uni_msg_types[] = {
+ { UNI_MSG_CALP, uni_calp_ie_tbl },
+ { UNI_MSG_CONN, uni_conn_ie_tbl },
+ { UNI_MSG_CACK, uni_cack_ie_tbl },
+ { UNI_MSG_SETU, uni_setu_ie_tbl },
+ { UNI_MSG_RLSE, uni_rlse_ie_tbl },
+ { UNI_MSG_RLSC, uni_rlsc_ie_tbl },
+ { UNI_MSG_RSTR, uni_rstr_ie_tbl },
+ { UNI_MSG_RSTA, uni_rsta_ie_tbl },
+ { UNI_MSG_STAT, uni_stat_ie_tbl },
+ { UNI_MSG_SENQ, uni_senq_ie_tbl },
+ { UNI_MSG_ADDP, uni_addp_ie_tbl },
+ { UNI_MSG_ADPA, uni_adpa_ie_tbl },
+ { UNI_MSG_ADPR, uni_adpr_ie_tbl },
+ { UNI_MSG_DRPP, uni_drpp_ie_tbl },
+ { UNI_MSG_DRPA, uni_drpa_ie_tbl },
+};
+
+
+/*
+ * Table of information elements
+ */
+static struct ie_ent ie_table[] = {
+ { UNI_IE_AALP, 5, 16, UNI_MSG_IE_AALP, usf_dec_ie_aalp },
+ { UNI_IE_CLRT, 0, 26, UNI_MSG_IE_CLRT, usf_dec_ie_clrt },
+ { UNI_IE_BBCP, 2, 3, UNI_MSG_IE_BBCP, usf_dec_ie_bbcp },
+ { UNI_IE_BHLI, 1, 9, UNI_MSG_IE_BHLI, usf_dec_ie_bhli },
+ { UNI_IE_BLLI, 0, 13, UNI_MSG_IE_BLLI, usf_dec_ie_blli },
+ { UNI_IE_CLST, 1, 1, UNI_MSG_IE_CLST, usf_dec_ie_clst },
+ { UNI_IE_CDAD, 1, 21, UNI_MSG_IE_CDAD, usf_dec_ie_cdad },
+ { UNI_IE_CDSA, 1, 21, UNI_MSG_IE_CDSA, usf_dec_ie_cdsa },
+ { UNI_IE_CGAD, 1, 22, UNI_MSG_IE_CGAD, usf_dec_ie_cgad },
+ { UNI_IE_CGSA, 1, 21, UNI_MSG_IE_CGSA, usf_dec_ie_cgsa },
+ { UNI_IE_CAUS, 2, 30, UNI_MSG_IE_CAUS, usf_dec_ie_caus },
+ { UNI_IE_CNID, 5, 5, UNI_MSG_IE_CNID, usf_dec_ie_cnid },
+ { UNI_IE_QOSP, 2, 2, UNI_MSG_IE_QOSP, usf_dec_ie_qosp },
+ { UNI_IE_BRPI, 1, 1, UNI_MSG_IE_BRPI, usf_dec_ie_brpi },
+ { UNI_IE_RSTI, 1, 1, UNI_MSG_IE_RSTI, usf_dec_ie_rsti },
+ { UNI_IE_BLSH, 1, 1, UNI_MSG_IE_ERR, usf_dec_ie_uimp },
+ { UNI_IE_BNSH, 1, 1, UNI_MSG_IE_ERR, usf_dec_ie_uimp },
+ { UNI_IE_BSDC, 1, 1, UNI_MSG_IE_BSDC, usf_dec_ie_bsdc },
+ { UNI_IE_TRNT, 1, 5, UNI_MSG_IE_TRNT, usf_dec_ie_trnt },
+ { UNI_IE_EPRF, 3, 3, UNI_MSG_IE_ERR, usf_dec_ie_uimp },
+ { UNI_IE_EPST, 1, 1, UNI_MSG_IE_ERR, usf_dec_ie_uimp },
+ { 0, 0, 0, 0, 0 }
+};
+
+/*
+ * Decoding table for AAL 1
+ */
+struct ie_decode_tbl ie_aal1_tbl[] = {
+ { 133, 1, IE_OFF_SIZE(ie_aalp_1_subtype) },
+ { 134, 1, IE_OFF_SIZE(ie_aalp_1_cbr_rate) },
+ { 135, 2, IE_OFF_SIZE(ie_aalp_1_multiplier) },
+ { 136, 1, IE_OFF_SIZE(ie_aalp_1_clock_recovery) },
+ { 137, 1, IE_OFF_SIZE(ie_aalp_1_error_correction) },
+ { 138, 1, IE_OFF_SIZE(ie_aalp_1_struct_data_tran) },
+ { 139, 1, IE_OFF_SIZE(ie_aalp_1_partial_cells) },
+ { 0, 0, 0, 0 }
+};
+
+/*
+ * Decoding table for AAL 3/4
+ */
+struct ie_decode_tbl ie_aal4_tbl_30[] = {
+ { 140, 2, IE_OFF_SIZE(ie_aalp_4_fwd_max_sdu) },
+ { 129, 2, IE_OFF_SIZE(ie_aalp_4_bkwd_max_sdu) },
+ { 130, 2, IE_OFF_SIZE(ie_aalp_4_mid_range) },
+ { 131, 1, IE_OFF_SIZE(ie_aalp_4_mode) },
+ { 132, 1, IE_OFF_SIZE(ie_aalp_4_sscs_type) },
+ { 0, 0, 0, 0 }
+};
+struct ie_decode_tbl ie_aal4_tbl_31[] = {
+ { 140, 2, IE_OFF_SIZE(ie_aalp_4_fwd_max_sdu) },
+ { 129, 2, IE_OFF_SIZE(ie_aalp_4_bkwd_max_sdu) },
+ { 130, 4, IE_OFF_SIZE(ie_aalp_4_mid_range) },
+ { 132, 1, IE_OFF_SIZE(ie_aalp_4_sscs_type) },
+ { 0, 0, 0, 0 }
+};
+
+/*
+ * Decoding table for AAL 5
+ */
+struct ie_decode_tbl ie_aal5_tbl_30[] = {
+ { 140, 2, IE_OFF_SIZE(ie_aalp_5_fwd_max_sdu) },
+ { 129, 2, IE_OFF_SIZE(ie_aalp_5_bkwd_max_sdu) },
+ { 131, 1, IE_OFF_SIZE(ie_aalp_5_mode) },
+ { 132, 1, IE_OFF_SIZE(ie_aalp_5_sscs_type) },
+ { 0, 0, 0, 0 }
+};
+struct ie_decode_tbl ie_aal5_tbl_31[] = {
+ { 140, 2, IE_OFF_SIZE(ie_aalp_5_fwd_max_sdu) },
+ { 129, 2, IE_OFF_SIZE(ie_aalp_5_bkwd_max_sdu) },
+ { 132, 1, IE_OFF_SIZE(ie_aalp_5_sscs_type) },
+ { 0, 0, 0, 0 }
+};
+
+/*
+ * Decoding table for ATM user cell rate
+ */
+struct ie_decode_tbl ie_clrt_tbl[] = {
+ {UNI_IE_CLRT_FWD_PEAK_ID, 3, IE_OFF_SIZE(ie_clrt_fwd_peak)},
+ {UNI_IE_CLRT_BKWD_PEAK_ID, 3, IE_OFF_SIZE(ie_clrt_bkwd_peak)},
+ {UNI_IE_CLRT_FWD_PEAK_01_ID, 3, IE_OFF_SIZE(ie_clrt_fwd_peak_01)},
+ {UNI_IE_CLRT_BKWD_PEAK_01_ID, 3, IE_OFF_SIZE(ie_clrt_bkwd_peak_01)},
+ {UNI_IE_CLRT_FWD_SUST_ID, 3, IE_OFF_SIZE(ie_clrt_fwd_sust)},
+ {UNI_IE_CLRT_BKWD_SUST_ID, 3, IE_OFF_SIZE(ie_clrt_bkwd_sust)},
+ {UNI_IE_CLRT_FWD_SUST_01_ID, 3, IE_OFF_SIZE(ie_clrt_fwd_sust_01)},
+ {UNI_IE_CLRT_BKWD_SUST_01_ID, 3, IE_OFF_SIZE(ie_clrt_bkwd_sust_01)},
+ {UNI_IE_CLRT_FWD_BURST_ID, 3, IE_OFF_SIZE(ie_clrt_fwd_burst)},
+ {UNI_IE_CLRT_BKWD_BURST_ID, 3, IE_OFF_SIZE(ie_clrt_bkwd_burst)},
+ {UNI_IE_CLRT_FWD_BURST_01_ID, 3, IE_OFF_SIZE(ie_clrt_fwd_burst_01)},
+ {UNI_IE_CLRT_BKWD_BURST_01_ID, 3, IE_OFF_SIZE(ie_clrt_bkwd_burst_01)},
+ {UNI_IE_CLRT_BEST_EFFORT_ID, 0, IE_OFF_SIZE(ie_clrt_best_effort)},
+ {UNI_IE_CLRT_TM_OPTIONS_ID, 1, IE_OFF_SIZE(ie_clrt_tm_options)},
+ {0, 0, 0, 0 }
+};
+
+/*
+ * IEs initialized to empty values
+ */
+struct ie_aalp ie_aalp_absent = {
+ T_ATM_ABSENT
+};
+
+struct ie_clrt ie_clrt_absent = {
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT
+};
+
+struct ie_bbcp ie_bbcp_absent = {
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT
+};
+
+struct ie_bhli ie_bhli_absent = {
+ T_ATM_ABSENT,
+ { 0, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+struct ie_blli ie_blli_absent = {
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ { 0, 0, 0 },
+ { 0, 0 }
+};
+
+struct ie_clst ie_clst_absent = {
+ T_ATM_ABSENT
+};
+
+struct ie_cdad ie_cdad_absent = {
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ { T_ATM_ABSENT, 0 }
+};
+
+struct ie_cdsa ie_cdsa_absent = {
+ { T_ATM_ABSENT, 0 }
+};
+
+struct ie_cgad ie_cgad_absent = {
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ { T_ATM_ABSENT, 0 }
+};
+
+struct ie_cgsa ie_cgsa_absent = {
+ { T_ATM_ABSENT, 0 }
+};
+
+struct ie_caus ie_caus_absent = {
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ 0
+};
+
+struct ie_cnid ie_cnid_absent = {
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ T_ATM_ABSENT
+};
+
+struct ie_qosp ie_qosp_absent = {
+ T_ATM_ABSENT,
+ T_ATM_ABSENT
+};
+
+struct ie_brpi ie_brpi_absent = {
+ T_ATM_ABSENT
+};
+
+struct ie_rsti ie_rsti_absent = {
+ T_ATM_ABSENT
+};
+
+struct ie_blsh ie_blsh_absent = {
+ T_ATM_ABSENT
+};
+
+struct ie_bnsh ie_bnsh_absent = {
+ T_ATM_ABSENT
+};
+
+struct ie_bsdc ie_bsdc_absent = {
+ T_ATM_ABSENT
+};
+
+struct ie_trnt ie_trnt_absent = {
+ T_ATM_ABSENT,
+ T_ATM_ABSENT,
+ 0
+};
+
+struct ie_eprf ie_eprf_absent = {
+ T_ATM_ABSENT,
+ T_ATM_ABSENT
+};
+
+struct ie_epst ie_epst_absent = {
+ T_ATM_ABSENT
+};
+
+
+/*
+ * Decode a UNI signalling message
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * msg pointer to a signalling message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+usf_dec_msg(usf, msg)
+ struct usfmt *usf;
+ struct unisig_msg *msg;
+{
+ int i, len, rc;
+ short s;
+ u_char c, *ie_tbl;
+ struct ie_generic *ie;
+
+ ATM_DEBUG2("usf_dec_msg: usf=0x%x, msg=0x%x\n", (int) usf,
+ (int) msg);
+
+ /*
+ * Check the total message length
+ */
+ if (usf_count(usf) < UNI_MSG_MIN_LEN) {
+ return(EIO);
+ }
+
+ /*
+ * Get and check the protocol discriminator
+ */
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ if (c != UNI_MSG_DISC_Q93B)
+ return(EIO);
+
+ /*
+ * Get and check the call reference length
+ */
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ if (c != 3)
+ return(EIO);
+
+ /*
+ * Get the call reference
+ */
+ rc = usf_int3(usf, &msg->msg_call_ref);
+ if (rc)
+ return(rc);
+
+ /*
+ * Get the message type
+ */
+ rc = usf_byte(usf, &msg->msg_type);
+ if (rc)
+ return(rc);
+
+ /*
+ * Get the message type extension
+ */
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ msg->msg_type_flag = (c >> UNI_MSG_TYPE_FLAG_SHIFT) &
+ UNI_MSG_TYPE_FLAG_MASK;
+ msg->msg_type_action = c & UNI_MSG_TYPE_ACT_MASK;
+
+ /*
+ * Get the message length and make sure we actually have
+ * enough data for the whole message
+ */
+ rc = usf_short(usf, &s);
+ if (rc)
+ return(rc);
+ msg->msg_length = s;
+ if (usf_count(usf) != msg->msg_length) {
+ return(EMSGSIZE);
+ }
+
+ /*
+ * Process information elements
+ */
+ len = msg->msg_length;
+ while (len) {
+ ALLOC_IE(ie);
+ rc = usf_dec_ie(usf, msg, ie);
+ if (rc) {
+ atm_free(ie);
+ return(rc);
+ }
+ len -= (ie->ie_length + UNI_IE_HDR_LEN);
+ }
+
+ /*
+ * Make sure that mandatory IEs are included and
+ * unwanted ones aren't
+ */
+ for (i=0; msg->msg_type!=uni_msg_types[i].msg_type &&
+ uni_msg_types[i].msg_type!=0; i++) {
+ }
+ if (!uni_msg_types[i].msg_ie_tbl)
+ goto done;
+
+ /*
+ * If the message type is in the table, check the IEs.
+ * If it isn't, the receive routine will catch the error.
+ */
+ ie_tbl = uni_msg_types[i].msg_ie_tbl;
+ for (i=0; i<UNI_MSG_IE_CNT-1; i++) {
+ switch(ie_tbl[i]) {
+ case IE_MAND:
+ if (!msg->msg_ie_vec[i]) {
+ /*
+ * Mandatory IE missing
+ */
+ ALLOC_IE(ie);
+ ie->ie_ident = unisig_ie_ident_vec[i];
+ ie->ie_err_cause = UNI_IE_CAUS_MISSING;
+ MSG_IE_ADD(msg, ie, UNI_MSG_IE_ERR);
+ }
+ break;
+ case IE_NA:
+ if (msg->msg_ie_vec[i]) {
+ /*
+ * Disallowed IE present
+ */
+ ie = msg->msg_ie_vec[i];
+ msg->msg_ie_vec[i] =
+ (struct ie_generic *) 0;
+ MSG_IE_ADD(msg, ie, UNI_MSG_IE_ERR);
+ while (ie) {
+ ie->ie_err_cause =
+ UNI_IE_CAUS_IEEXIST;
+ ie = ie->ie_next;
+ }
+ }
+ break;
+ case IE_OPT:
+ break;
+ }
+ }
+
+done:
+ return(0);
+}
+
+
+/*
+ * Decode an information element
+ *
+ * This routine will be called repeatedly as long as there are
+ * information elements left to be decoded. It will decode the
+ * first part of the IE, look its type up in a table, and call
+ * the appropriate routine to decode the rest. After an IE is
+ * successfully decoded, it is linked into the UNI signalling
+ * message structure. If an error is discovered, the IE is linked
+ * into the IE error chain and an error cause is set in the header.
+ *
+ * Arguments:
+ * usf pointer to a UNISIG formatting structure
+ * msg pointer to a UNISIG message structure
+ * ie pointer to a generic IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_dec_ie(usf, msg, ie)
+ struct usfmt *usf;
+ struct unisig_msg *msg;
+ struct ie_generic *ie;
+{
+ int i, ie_index, rc;
+
+ /*
+ * Decode the IE header (identifier, instruction field,
+ * and length)
+ */
+ rc = usf_dec_ie_hdr(usf, ie);
+ if (rc)
+ return(rc);
+ /*
+ * Ignore the IE if it is of zero length.
+ */
+ if (!ie->ie_length) {
+ atm_free(ie);
+ return(0);
+ }
+
+ /*
+ * Look up the information element in the table
+ */
+ for (i=0; (ie->ie_ident != ie_table[i].ident) &&
+ (ie_table[i].decode != NULL); i++) {
+ }
+ if (ie_table[i].decode == NULL) {
+ /*
+ * Unrecognized IE
+ */
+ ie_index = UNI_MSG_IE_ERR;
+ } else {
+ ie_index = ie_table[i].p_idx;
+ }
+
+ /*
+ * Check for unimplemented or unrecognized IEs
+ */
+ if (ie_index == UNI_MSG_IE_ERR) {
+ ie->ie_err_cause = UNI_IE_CAUS_IEEXIST;
+
+ /*
+ * Skip over the invalid IE
+ */
+ rc = usf_dec_ie_uimp(usf, ie);
+ if (rc)
+ return(rc);
+ goto done;
+ }
+
+ /*
+ * Check the length against the IE table
+ */
+ if (ie->ie_length < ie_table[i].min_len ||
+ ie->ie_length > ie_table[i].max_len) {
+ ie_index = UNI_MSG_IE_ERR;
+ ie->ie_err_cause = UNI_IE_CAUS_IECONTENT;
+
+ /*
+ * Skip over the invalid IE
+ */
+ rc = usf_dec_ie_uimp(usf, ie);
+ if (rc)
+ return(rc);
+ goto done;
+ }
+
+ /*
+ * Process the IE by calling the function indicated
+ * in the IE table
+ */
+ rc = ie_table[i].decode(usf, ie);
+ if (rc)
+ return(rc);
+
+ /*
+ * Link the IE into the signalling message
+ */
+done:
+ if (ie->ie_err_cause) {
+ ie_index = UNI_MSG_IE_ERR;
+ }
+ MSG_IE_ADD(msg, ie, ie_index);
+
+ return(0);
+}
+
+
+/*
+ * Decode an information element header
+ *
+ * Arguments:
+ * usf pointer to a UNISIG formatting structure
+ * ie pointer to a generic IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_dec_ie_hdr(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ u_char c;
+ short s;
+ int rc;
+
+ /*
+ * Get the IE identifier
+ */
+ rc = usf_byte(usf, &ie->ie_ident);
+ if (rc)
+ return(rc);
+
+ /*
+ * Get the extended type
+ */
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_coding = (c >> UNI_IE_CODE_SHIFT) & UNI_IE_CODE_MASK;
+ ie->ie_flag = (c >> UNI_IE_FLAG_SHIFT) & UNI_IE_FLAG_MASK;
+ ie->ie_action = c & UNI_IE_ACT_MASK;
+
+ /*
+ * Get the length.
+ */
+ rc = usf_short(usf, &s);
+ if (rc)
+ return(rc);
+ ie->ie_length = s;
+
+ return(0);
+}
+
+
+/*
+ * Decode an AAL parameters information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to an AAL parms IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_dec_ie_aalp(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int i, rc = 0;
+
+ /*
+ * Clear the IE
+ */
+ KM_COPY(&ie_aalp_absent, &ie->ie_u.ie_aalp,
+ sizeof(ie_aalp_absent));
+
+ /*
+ * Get the AAL type
+ */
+ rc = usf_byte(usf, &ie->ie_aalp_aal_type);
+ if (rc)
+ return(rc);
+
+ /*
+ * Subtract the length of the AAL type from the total.
+ * It will be readjusted after usf_dec_ie_ident is finished.
+ */
+ ie->ie_length--;
+
+ /*
+ * Process based on AAL type
+ */
+ switch (ie->ie_aalp_aal_type) {
+ case UNI_IE_AALP_AT_AAL1:
+ /*
+ * Clear the AAL 1 subparameters
+ */
+ ie->ie_aalp_1_subtype = T_ATM_ABSENT;
+ ie->ie_aalp_1_cbr_rate = T_ATM_ABSENT;
+ ie->ie_aalp_1_multiplier = T_ATM_ABSENT;
+ ie->ie_aalp_1_clock_recovery = T_ATM_ABSENT;
+ ie->ie_aalp_1_error_correction = T_ATM_ABSENT;
+ ie->ie_aalp_1_struct_data_tran = T_ATM_ABSENT;
+ ie->ie_aalp_1_partial_cells = T_ATM_ABSENT;
+
+ /*
+ * Parse the AAL fields based on their IDs
+ */
+ rc = usf_dec_ie_ident(usf, ie, ie_aal1_tbl);
+ break;
+ case UNI_IE_AALP_AT_AAL3:
+ /*
+ * Clear the AAL 3/4 subparameters
+ */
+ ie->ie_aalp_4_fwd_max_sdu = T_ATM_ABSENT;
+ ie->ie_aalp_4_bkwd_max_sdu = T_ATM_ABSENT;
+ ie->ie_aalp_4_mid_range = T_ATM_ABSENT;
+ ie->ie_aalp_4_mode = T_ATM_ABSENT;
+ ie->ie_aalp_4_sscs_type = T_ATM_ABSENT;
+
+ /*
+ * Parse the AAL fields based on their IDs
+ */
+ if (usf->usf_sig->us_proto == ATM_SIG_UNI30)
+ rc = usf_dec_ie_ident(usf, ie, ie_aal4_tbl_30);
+ else
+ rc = usf_dec_ie_ident(usf, ie, ie_aal4_tbl_31);
+
+ /*
+ * If either forward or backward maximum SDU
+ * size is specified, the other must also be
+ * specified.
+ */
+ if ((ie->ie_aalp_4_fwd_max_sdu != T_ATM_ABSENT &&
+ ie->ie_aalp_4_bkwd_max_sdu == T_ATM_ABSENT) ||
+ (ie->ie_aalp_4_fwd_max_sdu == T_ATM_ABSENT &&
+ ie->ie_aalp_4_bkwd_max_sdu != T_ATM_ABSENT)) {
+ ie->ie_err_cause = UNI_IE_CAUS_IECONTENT;
+ }
+ break;
+ case UNI_IE_AALP_AT_AAL5:
+ /*
+ * Clear the AAL 5 subparameters
+ */
+ ie->ie_aalp_5_fwd_max_sdu = T_ATM_ABSENT;
+ ie->ie_aalp_5_bkwd_max_sdu = T_ATM_ABSENT;
+ ie->ie_aalp_5_mode = T_ATM_ABSENT;
+ ie->ie_aalp_5_sscs_type = T_ATM_ABSENT;
+
+ /*
+ * Parse the AAL fields based on their IDs
+ */
+ if (usf->usf_sig->us_proto == ATM_SIG_UNI30)
+ rc = usf_dec_ie_ident(usf, ie, ie_aal5_tbl_30);
+ else
+ rc = usf_dec_ie_ident(usf, ie, ie_aal5_tbl_31);
+
+ /*
+ * If either forward or backward maximum SDU
+ * size is specified, the other must also be
+ * specified.
+ */
+ if ((ie->ie_aalp_5_fwd_max_sdu != T_ATM_ABSENT &&
+ ie->ie_aalp_5_bkwd_max_sdu == T_ATM_ABSENT) ||
+ (ie->ie_aalp_5_fwd_max_sdu == T_ATM_ABSENT &&
+ ie->ie_aalp_5_bkwd_max_sdu != T_ATM_ABSENT)) {
+ ie->ie_err_cause = UNI_IE_CAUS_IECONTENT;
+ }
+ break;
+ case UNI_IE_AALP_AT_AALU:
+ /*
+ * Check user parameter length
+ */
+ if (ie->ie_length >
+ sizeof(ie->ie_aalp_user_info) +
+ 1) {
+ ie->ie_err_cause = UNI_IE_CAUS_IECONTENT;
+ }
+
+ /*
+ * Get the user data
+ */
+ i = 0;
+ while (i < ie->ie_length - 2) {
+ rc = usf_byte(usf, &ie->ie_aalp_user_info[i]);
+ if (rc)
+ break;
+ i++;
+ }
+ break;
+ default:
+ ie->ie_err_cause = UNI_IE_CAUS_IECONTENT;
+ }
+ ie->ie_length++;
+
+ return(rc);
+}
+
+
+/*
+ * Decode a user cell rate information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_dec_ie_clrt(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int rc;
+
+ /*
+ * Clear the IE
+ */
+ KM_COPY(&ie_clrt_absent, &ie->ie_u.ie_clrt,
+ sizeof(ie_clrt_absent));
+
+ /*
+ * Parse the IE using field identifiers
+ */
+ rc = usf_dec_ie_ident(usf, ie, ie_clrt_tbl);
+ return(rc);
+}
+
+
+/*
+ * Decode a broadband bearer capability information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_dec_ie_bbcp(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int rc;
+ u_char c;
+
+ /*
+ * Clear the IE
+ */
+ KM_COPY(&ie_bbcp_absent, &ie->ie_u.ie_bbcp,
+ sizeof(ie_bbcp_absent));
+
+ /*
+ * Get the broadband bearer class
+ */
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_bbcp_bearer_class = c & UNI_IE_BBCP_BC_MASK;
+
+ /*
+ * If the broadband bearer class was X, the next
+ * byte has the traffic type and timing requirements
+ */
+ if (ie->ie_bbcp_bearer_class == UNI_IE_BBCP_BC_BCOB_X &&
+ !(c & UNI_IE_EXT_BIT)) {
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_bbcp_traffic_type = (c >> UNI_IE_BBCP_TT_SHIFT) &
+ UNI_IE_BBCP_TT_MASK;
+ ie->ie_bbcp_timing_req = c & UNI_IE_BBCP_TR_MASK;
+ }
+
+ /*
+ * Get the clipping and user plane connection configuration
+ */
+ if (c & UNI_IE_EXT_BIT) {
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_bbcp_clipping = (c >> UNI_IE_BBCP_SC_SHIFT) &
+ UNI_IE_BBCP_SC_MASK;
+ ie->ie_bbcp_conn_config = c & UNI_IE_BBCP_CC_MASK;
+ }
+
+ return(0);
+}
+
+
+/*
+ * Decode a broadband high layer information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_dec_ie_bhli(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int i, rc;
+ u_char c;
+
+ /*
+ * Clear the IE
+ */
+ KM_COPY(&ie_bhli_absent, &ie->ie_u.ie_bhli,
+ sizeof(ie_bhli_absent));
+
+ /*
+ * Get the high layer information type
+ */
+ rc = usf_ext(usf, &i);
+ ie->ie_bhli_type = i & UNI_IE_EXT_MASK;
+ if (rc)
+ return(rc);
+
+ /*
+ * What comes next depends on the type
+ */
+ switch (ie->ie_bhli_type) {
+ case UNI_IE_BHLI_TYPE_ISO:
+ case UNI_IE_BHLI_TYPE_USER:
+ /*
+ * ISO or user-specified parameters -- take the
+ * length of information from the IE length
+ */
+ for (i=0; i<ie->ie_length-1; i++) {
+ rc = usf_byte(usf, &ie->ie_bhli_info[i]);
+ if (rc)
+ return(rc);
+ }
+ break;
+ case UNI_IE_BHLI_TYPE_HLP:
+ /*
+ * Make sure the IE is long enough for the high
+ * layer profile information, then get it
+ */
+ if (usf->usf_sig->us_proto != ATM_SIG_UNI30)
+ ie->ie_err_cause = UNI_IE_CAUS_IECONTENT;
+ if (ie->ie_length < UNI_IE_BHLI_HLP_LEN+1)
+ ie->ie_err_cause = UNI_IE_CAUS_IECONTENT;
+ for (i=0; i<ie->ie_length &&
+ i<UNI_IE_BHLI_HLP_LEN; i++) {
+ rc = usf_byte(usf, &ie->ie_bhli_info[i]);
+ if (rc)
+ return(rc);
+ }
+ break;
+ case UNI_IE_BHLI_TYPE_VSA:
+ /*
+ * Make sure the IE is long enough for the vendor-
+ * specific application information, then get it
+ */
+ if (ie->ie_length < UNI_IE_BHLI_VSA_LEN+1)
+ ie->ie_err_cause = UNI_IE_CAUS_IECONTENT;
+ for (i=0; i<ie->ie_length &&
+ i<UNI_IE_BHLI_VSA_LEN; i++) {
+ rc = usf_byte(usf, &ie->ie_bhli_info[i]);
+ if (rc)
+ return(rc);
+ }
+ break;
+ default:
+ ie->ie_err_cause = UNI_IE_CAUS_IECONTENT;
+ for (i=0; i<ie->ie_length; i++) {
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ }
+ }
+
+ return(0);
+}
+
+
+/*
+ * Decode a broadband low layer information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_dec_ie_blli(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ u_char c, id;
+ int bc, i, rc;
+ u_int ipi;
+
+ /*
+ * Clear the IE
+ */
+ KM_COPY(&ie_blli_absent, &ie->ie_u.ie_blli,
+ sizeof(ie_blli_absent));
+
+ /*
+ * Get paramteters for the protocol layers as long as
+ * there is still information left in the IE
+ */
+ bc = ie->ie_length;
+ while (bc) {
+ /*
+ * Get the type and process based on what it is
+ */
+ rc = usf_byte(usf, &id);
+ if (rc)
+ return(rc);
+ switch (((id & UNI_IE_EXT_MASK) >>
+ UNI_IE_BLLI_LID_SHIFT) &
+ UNI_IE_BLLI_LID_MASK) {
+ case UNI_IE_BLLI_L1_ID:
+ /*
+ * Layer 1 info
+ */
+ ie->ie_blli_l1_id = id & UNI_IE_BLLI_LP_MASK;
+ bc--;
+ break;
+ case UNI_IE_BLLI_L2_ID:
+ /*
+ * Layer 2 info--contents vary based on type
+ */
+ ie->ie_blli_l2_id = id & UNI_IE_BLLI_LP_MASK;
+ bc--;
+ if (id & UNI_IE_EXT_BIT)
+ break;
+ switch (ie->ie_blli_l2_id) {
+ case UNI_IE_BLLI_L2P_X25L:
+ case UNI_IE_BLLI_L2P_X25M:
+ case UNI_IE_BLLI_L2P_HDLC1:
+ case UNI_IE_BLLI_L2P_HDLC2:
+ case UNI_IE_BLLI_L2P_HDLC3:
+ case UNI_IE_BLLI_L2P_Q922:
+ case UNI_IE_BLLI_L2P_ISO7776:
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ bc--;
+ ie->ie_blli_l2_mode = (c >>
+ UNI_IE_BLLI_L2MODE_SHIFT) &
+ UNI_IE_BLLI_L2MODE_MASK;
+ if (!(c & UNI_IE_EXT_BIT))
+ break;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ bc--;
+ ie->ie_blli_l2_window =
+ c & UNI_IE_EXT_MASK;
+ break;
+ case UNI_IE_BLLI_L2P_USER:
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ bc--;
+ ie->ie_blli_l2_user_proto =
+ c & UNI_IE_EXT_MASK;
+ break;
+ }
+ break;
+ case UNI_IE_BLLI_L3_ID:
+ /*
+ * Layer 3 info--contents vary based on type
+ */
+ ie->ie_blli_l3_id = id & UNI_IE_BLLI_LP_MASK;
+ bc--;
+ switch (ie->ie_blli_l3_id) {
+ case UNI_IE_BLLI_L3P_X25:
+ case UNI_IE_BLLI_L3P_ISO8208:
+ case UNI_IE_BLLI_L3P_ISO8878:
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ bc--;
+ ie->ie_blli_l3_mode = (c >>
+ UNI_IE_BLLI_L3MODE_SHIFT) &
+ UNI_IE_BLLI_L3MODE_MASK;
+ if (!(c & UNI_IE_EXT_BIT))
+ break;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ bc--;
+ ie->ie_blli_l3_packet_size =
+ c & UNI_IE_BLLI_L3PS_MASK;
+ if (!(c & UNI_IE_EXT_BIT))
+ break;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ bc--;
+ ie->ie_blli_l3_window =
+ c & UNI_IE_EXT_MASK;
+ break;
+ case UNI_IE_BLLI_L3P_USER:
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ bc--;
+ ie->ie_blli_l3_mode =
+ c & UNI_IE_EXT_MASK;
+ break;
+ case UNI_IE_BLLI_L3P_ISO9577:
+ rc = usf_ext(usf, &ipi);
+ if (rc)
+ return(rc);
+ bc -= 2;
+ ie->ie_blli_l3_ipi = ipi >>
+ UNI_IE_BLLI_L3IPI_SHIFT;
+ if (ie->ie_blli_l3_ipi !=
+ UNI_IE_BLLI_L3IPI_SNAP)
+ break;
+
+ rc = usf_byte(usf, &c);
+ ie->ie_blli_l3_snap_id = c & UNI_IE_EXT_MASK;
+ if (rc)
+ return(rc);
+ bc --;
+
+ rc = usf_byte(usf,
+ &ie->ie_blli_l3_oui[0]);
+ if (rc)
+ return(rc);
+ rc = usf_byte(usf,
+ &ie->ie_blli_l3_oui[1]);
+ if (rc)
+ return(rc);
+ rc = usf_byte(usf,
+ &ie->ie_blli_l3_oui[2]);
+ if (rc)
+ return(rc);
+ rc = usf_byte(usf,
+ &ie->ie_blli_l3_pid[0]);
+ if (rc)
+ return(rc);
+ rc = usf_byte(usf,
+ &ie->ie_blli_l3_pid[1]);
+ if (rc)
+ return(rc);
+ bc -= 5;
+ break;
+ }
+ break;
+ default:
+ ie->ie_err_cause = UNI_IE_CAUS_IECONTENT;
+ for (i=0; i<ie->ie_length; i++) {
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ }
+ }
+ }
+
+ return(0);
+}
+
+
+/*
+ * Decode a call state information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_dec_ie_clst(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int rc;
+ u_char c;
+
+ /*
+ * Clear the IE
+ */
+ KM_COPY(&ie_clst_absent, &ie->ie_u.ie_clst,
+ sizeof(ie_clst_absent));
+
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_clst_state = c & UNI_IE_CLST_STATE_MASK;
+
+ return(0);
+}
+
+
+/*
+ * Decode a called party number information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_dec_ie_cdad(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int len, rc;
+ u_char c;
+
+ /*
+ * Clear the IE
+ */
+ KM_COPY(&ie_cdad_absent, &ie->ie_u.ie_cdad,
+ sizeof(ie_cdad_absent));
+
+ /*
+ * Get and check the numbering plan
+ */
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_cdad_plan = c & UNI_IE_CDAD_PLAN_MASK;
+ len = ie->ie_length - 1;
+ switch (ie->ie_cdad_plan) {
+ case UNI_IE_CDAD_PLAN_E164:
+ ie->ie_cdad_addr.address_format = T_ATM_E164_ADDR;
+ break;
+ case UNI_IE_CDAD_PLAN_NSAP:
+ ie->ie_cdad_addr.address_format = T_ATM_ENDSYS_ADDR;
+ break;
+ default:
+ /*
+ * Invalid numbering plan
+ */
+ ie->ie_err_cause = UNI_IE_CAUS_IECONTENT;
+ while (len) {
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ len--;
+ }
+
+ return(0);
+ }
+
+ /*
+ * Get the ATM address
+ */
+ rc = usf_dec_atm_addr(usf, &ie->ie_cdad_addr, len);
+ if (rc == EINVAL) {
+ ie->ie_err_cause = UNI_IE_CAUS_IECONTENT;
+ rc = 0;
+ }
+
+ return(rc);
+}
+
+
+/*
+ * Decode a called party subaddress information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_dec_ie_cdsa(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int len, rc;
+ u_char c;
+
+ /*
+ * Clear the IE
+ */
+ KM_COPY(&ie_cdsa_absent, &ie->ie_u.ie_cdsa,
+ sizeof(ie_cdsa_absent));
+
+ /*
+ * Get and check the subaddress type
+ */
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ len = ie->ie_length - 1;
+ if (((c >> UNI_IE_CDSA_TYPE_SHIFT) & UNI_IE_CDSA_TYPE_MASK) !=
+ UNI_IE_CDSA_TYPE_AESA) {
+ /*
+ * Invalid subaddress type
+ */
+ ie->ie_err_cause = UNI_IE_CAUS_IECONTENT;
+ while (len) {
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ len--;
+ }
+
+ return(0);
+ }
+
+ /*
+ * Get the ATM address
+ */
+ ie->ie_cdsa_addr.address_format = T_ATM_ENDSYS_ADDR;
+ rc = usf_dec_atm_addr(usf, &ie->ie_cdsa_addr, len);
+ if (rc == EINVAL) {
+ ie->ie_err_cause = UNI_IE_CAUS_IECONTENT;
+ rc = 0;
+ }
+
+ return(rc);
+}
+
+
+/*
+ * Decode a calling party number information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_dec_ie_cgad(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int len, rc;
+ u_char c;
+
+ /*
+ * Clear the IE
+ */
+ KM_COPY(&ie_cgad_absent, &ie->ie_u.ie_cgad,
+ sizeof(ie_cgad_absent));
+
+ /*
+ * Get and check the numbering plan
+ */
+ len = ie->ie_length;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_cgad_type = (c >> UNI_IE_CGAD_TYPE_SHIFT) &
+ UNI_IE_CGAD_TYPE_MASK;
+ ie->ie_cgad_plan = c & UNI_IE_CGAD_PLAN_MASK;
+ len--;
+ switch (ie->ie_cgad_plan) {
+ case UNI_IE_CGAD_PLAN_E164:
+ ie->ie_cgad_addr.address_format = T_ATM_E164_ADDR;
+ break;
+ case UNI_IE_CGAD_PLAN_NSAP:
+ ie->ie_cgad_addr.address_format = T_ATM_ENDSYS_ADDR;
+ break;
+ default:
+ ie->ie_err_cause = UNI_IE_CAUS_IECONTENT;
+ while (len) {
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ len--;
+ }
+
+ return(0);
+ }
+
+ /*
+ * Get the presentation and screening indicators, if present
+ */
+ if (!(c & UNI_IE_EXT_BIT)) {
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ len--;
+ ie->ie_cgad_pres_ind = (c >> UNI_IE_CGAD_PRES_SHIFT) &
+ UNI_IE_CGAD_PRES_MASK;
+ ie->ie_cgad_screen_ind = c & UNI_IE_CGAD_SCR_MASK;
+ } else {
+ ie->ie_cgad_pres_ind = 0;
+ ie->ie_cgad_screen_ind =0;
+ }
+
+ /*
+ * Get the ATM address
+ */
+ rc = usf_dec_atm_addr(usf, &ie->ie_cgad_addr, len);
+ if (rc == EINVAL) {
+ ie->ie_err_cause = UNI_IE_CAUS_IECONTENT;
+ rc = 0;
+ }
+
+ return(rc);
+}
+
+
+/*
+ * Decode a calling party subaddress information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_dec_ie_cgsa(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int len, rc;
+ u_char c;
+
+ /*
+ * Clear the IE
+ */
+ KM_COPY(&ie_cgsa_absent, &ie->ie_u.ie_cgsa,
+ sizeof(ie_cgsa_absent));
+
+ /*
+ * Get and check the subaddress type
+ */
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ len = ie->ie_length - 1;
+ if (((c >> UNI_IE_CGSA_TYPE_SHIFT) & UNI_IE_CGSA_TYPE_MASK) !=
+ UNI_IE_CGSA_TYPE_AESA) {
+ /*
+ * Invalid subaddress type
+ */
+ ie->ie_err_cause = UNI_IE_CAUS_IECONTENT;
+ while (len) {
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ len--;
+ }
+
+ return(0);
+ }
+
+ /*
+ * Get the ATM address
+ */
+ ie->ie_cgsa_addr.address_format = T_ATM_ENDSYS_ADDR;
+ rc = usf_dec_atm_addr(usf, &ie->ie_cgsa_addr, len);
+ if (rc == EINVAL) {
+ ie->ie_err_cause = UNI_IE_CAUS_IECONTENT;
+ rc = 0;
+ }
+
+ return(rc);
+}
+
+
+/*
+ * Decode a cause information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_dec_ie_caus(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int i, len, rc;
+ u_char c;
+
+ /*
+ * Clear the IE
+ */
+ KM_COPY(&ie_caus_absent, &ie->ie_u.ie_caus,
+ sizeof(ie_caus_absent));
+
+ /*
+ * Get the cause location
+ */
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_caus_loc = c & UNI_IE_CAUS_LOC_MASK;
+
+ /*
+ * Get the cause value
+ */
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_caus_cause = c & UNI_IE_EXT_MASK;
+
+ /*
+ * Get any included diagnostics
+ */
+ len = ie->ie_length - 2;
+ for (i = 0, ie->ie_caus_diag_len = 0;
+ len && i < sizeof(ie->ie_caus_diagnostic);
+ len--, i++, ie->ie_caus_diag_len++) {
+ rc = usf_byte(usf, &ie->ie_caus_diagnostic[i]);
+ if (rc)
+ return(rc);
+ }
+
+ return(0);
+}
+
+
+/*
+ * Decode a conection identifier information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_dec_ie_cnid(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int i, rc;
+
+ /*
+ * Clear the IE
+ */
+ KM_COPY(&ie_cnid_absent, &ie->ie_u.ie_cnid,
+ sizeof(ie_cnid_absent));
+
+ rc = usf_ext(usf, &i);
+ if (rc)
+ return(rc);
+ ie->ie_cnid_vp_sig = (i >> UNI_IE_CNID_VPSIG_SHIFT) &
+ UNI_IE_CNID_VPSIG_MASK;
+ ie->ie_cnid_pref_excl = i & UNI_IE_CNID_PREX_MASK;
+
+ rc = usf_short(usf, &ie->ie_cnid_vpci);
+ if (rc)
+ return(rc);
+ rc = usf_short(usf, &ie->ie_cnid_vci);
+ return(rc);
+}
+
+
+/*
+ * Decode a quality of service parameters information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_dec_ie_qosp(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int rc;
+
+ /*
+ * Clear the IE
+ */
+ KM_COPY(&ie_qosp_absent, &ie->ie_u.ie_qosp,
+ sizeof(ie_qosp_absent));
+
+ /*
+ * Get forward QoS class
+ */
+ rc = usf_byte(usf, &ie->ie_qosp_fwd_class);
+ if (rc)
+ return(rc);
+
+ /*
+ * Get backward QoS class
+ */
+ rc = usf_byte(usf, &ie->ie_qosp_bkwd_class);
+
+ return(rc);
+}
+
+
+/*
+ * Decode a broadband repeat indicator information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_dec_ie_brpi(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int rc;
+ u_char c;
+
+ /*
+ * Clear the IE
+ */
+ KM_COPY(&ie_brpi_absent, &ie->ie_u.ie_brpi,
+ sizeof(ie_brpi_absent));
+
+ /*
+ * Get the repeat indicator
+ */
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+
+ ie->ie_brpi_ind = c & UNI_IE_BRPI_IND_MASK;
+
+ return(0);
+}
+
+
+/*
+ * Decode a restart indicator information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_dec_ie_rsti(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int rc;
+ u_char c;
+
+ /*
+ * Clear the IE
+ */
+ KM_COPY(&ie_rsti_absent, &ie->ie_u.ie_rsti,
+ sizeof(ie_rsti_absent));
+
+ /*
+ * Get the restart class
+ */
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+
+ ie->ie_rsti_class = c & UNI_IE_RSTI_CLASS_MASK;
+
+ return(0);
+}
+
+
+/*
+ * Decode a broadband sending complete information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a broadband sending complete IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_dec_ie_bsdc(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int rc;
+ u_char c;
+
+ /*
+ * Clear the IE
+ */
+ KM_COPY(&ie_bsdc_absent, &ie->ie_u.ie_bsdc,
+ sizeof(ie_bsdc_absent));
+
+ /*
+ * Get the sending complete indicator
+ */
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+
+ /*
+ * Validate the indicator
+ */
+ c &= UNI_IE_EXT_MASK;
+ if (c != UNI_IE_BSDC_IND)
+ ie->ie_err_cause = UNI_IE_CAUS_IECONTENT;
+ ie->ie_bsdc_ind = c;
+
+ return(0);
+}
+
+
+/*
+ * Decode a transit network selection information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a transit network selection IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_dec_ie_trnt(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int i, len, rc;
+ u_char c;
+
+ /*
+ * Clear the IE
+ */
+ KM_COPY(&ie_trnt_absent, &ie->ie_u.ie_trnt,
+ sizeof(ie_trnt_absent));
+
+ /*
+ * Get the network ID type and plan
+ */
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_trnt_id_type = (c >> UNI_IE_TRNT_IDT_SHIFT) &
+ UNI_IE_TRNT_IDT_MASK;
+ ie->ie_trnt_id_plan = c & UNI_IE_TRNT_IDP_MASK;
+
+ /*
+ * Get the length of the network ID
+ */
+ len = ie->ie_length - 1;
+ ie->ie_trnt_id_len = MIN(len, sizeof(ie->ie_trnt_id));
+
+ /*
+ * Get the network ID
+ */
+ for (i=0; i<len; i++) {
+ if (i<sizeof(ie->ie_trnt_id))
+ rc = usf_byte(usf, &ie->ie_trnt_id[i]);
+ else
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ }
+
+ return(0);
+}
+
+
+/*
+ * Decode an unimplemented information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_dec_ie_uimp(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int i, rc;
+ u_char c;
+
+ /*
+ * Skip over the IE contents
+ */
+ for (i=0; i<ie->ie_length; i++) {
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ }
+
+ return(0);
+}
+
+
+/*
+ * Decode an information element using field identifiers
+ *
+ * The AAL parameters and ATM user cell rate IEs are formatted
+ * with a one-byte identifier preceeding each field. The routine
+ * parses these IEs by using a table which relates the field
+ * identifiers with the fields in the appropriate IE structure.
+ * Field order in the received message is immaterial.
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ * tbl pointer to an IE decoding table
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_dec_ie_ident(usf, ie, tbl)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+ struct ie_decode_tbl *tbl;
+{
+ int i, len, rc;
+ u_char c;
+ u_int8_t cv;
+ u_int16_t sv;
+ u_int32_t iv;
+ void *dest;
+
+ /*
+ * Scan through the IE
+ */
+ len = ie->ie_length;
+ while (len) {
+ /*
+ * Get the field identifier
+ */
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ len--;
+
+ /*
+ * Look up the field in the table
+ */
+ for (i=0; (tbl[i].ident != c) && tbl[i].len; i++) {
+ }
+ if (tbl[i].ident == 0) {
+ /*
+ * Bad subfield identifier -- flag an
+ * error and skip over the rest of the IE
+ */
+ ie->ie_err_cause = UNI_IE_CAUS_IECONTENT;
+ while (len) {
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ }
+ return(0);
+ }
+
+ /*
+ * Save final destination address
+ */
+ dest = (void *)((int)ie + tbl[i].f_offs);
+
+ /*
+ * Get the field value
+ */
+ switch (tbl[i].len) {
+ case 0:
+ cv = 1;
+ goto savec;
+
+ case 1:
+ rc = usf_byte(usf, &cv);
+ if (rc)
+ break;
+savec:
+ /*
+ * Save field value
+ */
+ switch (tbl[i].f_size) {
+ case 1:
+ *(u_int8_t *)dest = cv;
+ break;
+ case 2:
+ *(u_int16_t *)dest = cv;
+ break;
+ case 4:
+ *(u_int32_t *)dest = cv;
+ break;
+ default:
+ goto badtbl;
+ }
+ break;
+
+ case 2:
+ rc = usf_short(usf, &sv);
+ if (rc)
+ break;
+
+ /*
+ * Save field value
+ */
+ switch (tbl[i].f_size) {
+ case 2:
+ *(u_int16_t *)dest = sv;
+ break;
+ case 4:
+ *(u_int32_t *)dest = sv;
+ break;
+ default:
+ goto badtbl;
+ }
+ break;
+
+ case 3:
+ rc = usf_int3(usf, &iv);
+ goto savei;
+
+ case 4:
+ rc = usf_int(usf, &iv);
+savei:
+ /*
+ * Save field value
+ */
+ if (rc)
+ break;
+ switch (tbl[i].f_size) {
+ case 4:
+ *(u_int32_t *)dest = iv;
+ break;
+ default:
+ goto badtbl;
+ }
+ break;
+
+ default:
+badtbl:
+ log(LOG_ERR,
+ "uni decode: id=%d,len=%d,off=%d,size=%d\n",
+ tbl[i].ident, tbl[i].len,
+ tbl[i].f_offs, tbl[i].f_size);
+ rc = EFAULT;
+ break;
+ }
+
+ if (rc)
+ return(rc);
+
+ len -= tbl[i].len;
+
+ }
+
+ return(0);
+}
+
+
+/*
+ * Decode an ATM address
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * addr pointer to an ATM address structure
+ * len length of data remainig in the IE
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_dec_atm_addr(usf, addr, len)
+ struct usfmt *usf;
+ Atm_addr *addr;
+ int len;
+{
+ int rc;
+ u_char c, *cp;
+
+ /*
+ * Check the address type
+ */
+ addr->address_length = len;
+ switch (addr->address_format) {
+ case T_ATM_E164_ADDR:
+ if (len > sizeof(Atm_addr_e164)) {
+ goto flush;
+ }
+ cp = (u_char *) addr->address;
+ break;
+ case T_ATM_ENDSYS_ADDR:
+ if (len != sizeof(Atm_addr_nsap)) {
+ goto flush;
+ }
+ cp = (u_char *) addr->address;
+ break;
+ default:
+ /* Silence the compiler */
+ cp = NULL;
+ }
+
+ /*
+ * Get the ATM address
+ */
+ while (len) {
+ rc = usf_byte(usf, cp);
+ if (rc)
+ return(rc);
+ len--;
+ cp++;
+ }
+
+ return(0);
+
+flush:
+ while (len) {
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ len--;
+ }
+
+ return(EINVAL);
+}
diff --git a/sys/netatm/uni/unisig_decode.h b/sys/netatm/uni/unisig_decode.h
new file mode 100644
index 0000000..dbd184a
--- /dev/null
+++ b/sys/netatm/uni/unisig_decode.h
@@ -0,0 +1,87 @@
+/*
+ *
+ * ===================================
+ * 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: unisig_decode.h,v 1.5 1998/08/26 23:29:21 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI 3.0/3.1 Signalling Manager
+ * ----------------------------------------
+ *
+ * Message formats
+ *
+ */
+
+#ifndef _UNI_SIG_DECODE_H
+#define _UNI_SIG_DECODE_H
+
+
+/*
+ * Values specifying which IEs are required in messages
+ */
+#define IE_NA 0
+#define IE_MAND 1
+#define IE_OPT 2
+
+/*
+ * Structure for information element decoding information
+ */
+struct ie_ent {
+ u_char ident; /* IE identifier */
+ int min_len; /* Min. length */
+ int max_len; /* Max. length */
+ int p_idx; /* IE pointer index in msg */
+ int (*decode) /* Decoding function */
+ __P((struct usfmt *, struct ie_generic *));
+};
+
+/*
+ * Macro to give the offset of a field in a generic IE structure
+ */
+#define IE_OFFSET(f) \
+ ((int)&((struct ie_generic *) 0)->f)
+
+/*
+ * Macro to give the size of a field in a generic IE structure
+ */
+#define IE_FSIZE(f) \
+ (sizeof(((struct ie_generic *) 0)->f))
+
+#define IE_OFF_SIZE(f) IE_OFFSET(f),IE_FSIZE(f)
+
+
+/*
+ * Structure to define a field-driven decoding table (for AAL
+ * parameters and ATM user cell rate IEs)
+ */
+struct ie_decode_tbl {
+ u_char ident;
+ int len;
+ int f_offs;
+ int f_size;
+};
+
+#endif /* _UNI_SIG_DECODE_H */
diff --git a/sys/netatm/uni/unisig_encode.c b/sys/netatm/uni/unisig_encode.c
new file mode 100644
index 0000000..0920acc
--- /dev/null
+++ b/sys/netatm/uni/unisig_encode.c
@@ -0,0 +1,1681 @@
+/*
+ *
+ * ===================================
+ * 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: unisig_encode.c,v 1.11 1998/08/26 23:29:21 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI 3.0/3.1 Signalling Manager
+ * ----------------------------------------
+ *
+ * Message formatting module
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: unisig_encode.c,v 1.11 1998/08/26 23:29:21 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/unisig.h>
+#include <netatm/uni/unisig_var.h>
+#include <netatm/uni/unisig_msg.h>
+#include <netatm/uni/unisig_mbuf.h>
+#include <netatm/uni/unisig_decode.h>
+
+
+/*
+ * Local functions
+ */
+static int usf_enc_ie __P((struct usfmt *, struct ie_generic *));
+static int usf_enc_ie_aalp __P((struct usfmt *, struct ie_generic *));
+static int usf_enc_ie_clrt __P((struct usfmt *, struct ie_generic *));
+static int usf_enc_ie_bbcp __P((struct usfmt *, struct ie_generic *));
+static int usf_enc_ie_bhli __P((struct usfmt *, struct ie_generic *));
+static int usf_enc_ie_blli __P((struct usfmt *, struct ie_generic *));
+static int usf_enc_ie_clst __P((struct usfmt *, struct ie_generic *));
+static int usf_enc_ie_cdad __P((struct usfmt *, struct ie_generic *));
+static int usf_enc_ie_cdsa __P((struct usfmt *, struct ie_generic *));
+static int usf_enc_ie_cgad __P((struct usfmt *, struct ie_generic *));
+static int usf_enc_ie_cgsa __P((struct usfmt *, struct ie_generic *));
+static int usf_enc_ie_caus __P((struct usfmt *, struct ie_generic *));
+static int usf_enc_ie_cnid __P((struct usfmt *, struct ie_generic *));
+static int usf_enc_ie_qosp __P((struct usfmt *, struct ie_generic *));
+static int usf_enc_ie_brpi __P((struct usfmt *, struct ie_generic *));
+static int usf_enc_ie_rsti __P((struct usfmt *, struct ie_generic *));
+static int usf_enc_ie_bsdc __P((struct usfmt *, struct ie_generic *));
+static int usf_enc_ie_trnt __P((struct usfmt *, struct ie_generic *));
+static int usf_enc_ie_uimp __P((struct usfmt *, struct ie_generic *));
+static int usf_enc_ie_ident __P((struct usfmt *, struct ie_generic *,
+ struct ie_decode_tbl *));
+static int usf_enc_atm_addr __P((struct usfmt *, Atm_addr *));
+
+
+/*
+ * Local variables
+ */
+static struct {
+ u_char ident; /* IE identifier */
+ int (*encode) __P((struct usfmt *, struct ie_generic *));
+ /* Encoding function */
+} ie_table[] = {
+ { UNI_IE_AALP, usf_enc_ie_aalp },
+ { UNI_IE_CLRT, usf_enc_ie_clrt },
+ { UNI_IE_BBCP, usf_enc_ie_bbcp },
+ { UNI_IE_BHLI, usf_enc_ie_bhli },
+ { UNI_IE_BLLI, usf_enc_ie_blli },
+ { UNI_IE_CLST, usf_enc_ie_clst },
+ { UNI_IE_CDAD, usf_enc_ie_cdad },
+ { UNI_IE_CDSA, usf_enc_ie_cdsa },
+ { UNI_IE_CGAD, usf_enc_ie_cgad },
+ { UNI_IE_CGSA, usf_enc_ie_cgsa },
+ { UNI_IE_CAUS, usf_enc_ie_caus },
+ { UNI_IE_CNID, usf_enc_ie_cnid },
+ { UNI_IE_QOSP, usf_enc_ie_qosp },
+ { UNI_IE_BRPI, usf_enc_ie_brpi },
+ { UNI_IE_RSTI, usf_enc_ie_rsti },
+ { UNI_IE_BLSH, usf_enc_ie_uimp },
+ { UNI_IE_BNSH, usf_enc_ie_uimp },
+ { UNI_IE_BSDC, usf_enc_ie_bsdc },
+ { UNI_IE_TRNT, usf_enc_ie_trnt },
+ { UNI_IE_EPRF, usf_enc_ie_uimp },
+ { UNI_IE_EPST, usf_enc_ie_uimp },
+ { 0, 0 }
+};
+
+extern struct ie_decode_tbl ie_aal1_tbl[];
+extern struct ie_decode_tbl ie_aal4_tbl_30[];
+extern struct ie_decode_tbl ie_aal4_tbl_31[];
+extern struct ie_decode_tbl ie_aal5_tbl_30[];
+extern struct ie_decode_tbl ie_aal5_tbl_31[];
+extern struct ie_decode_tbl ie_clrt_tbl[];
+
+
+/*
+ * Encode a UNI signalling message
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * msg pointer to a signalling message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+usf_enc_msg(usf, msg)
+ struct usfmt *usf;
+ struct unisig_msg *msg;
+{
+ int i, len, rc;
+ u_char c;
+ u_char *lp0, *lp1;
+ struct ie_generic *ie;
+
+ union {
+ short s;
+ u_char sb[sizeof(short)];
+ } su;
+
+ ATM_DEBUG2("usf_enc_msg: usf=0x%x, msg=0x%x\n",
+ (int)usf, (int)msg);
+
+ /*
+ * Encode the protocol discriminator
+ */
+ c = UNI_MSG_DISC_Q93B;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+
+ /*
+ * Encode the call reference length
+ */
+ c = 3;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+
+ /*
+ * Encode the call reference
+ */
+ rc = usf_int3(usf, &msg->msg_call_ref);
+ if (rc)
+ return(rc);
+
+ /*
+ * Encode the message type
+ */
+ rc = usf_byte(usf, &msg->msg_type);
+ if (rc)
+ return(rc);
+
+ /*
+ * Encode the message type extension
+ */
+ c = ((msg->msg_type_flag & UNI_MSG_TYPE_FLAG_MASK) <<
+ UNI_MSG_TYPE_FLAG_SHIFT) +
+ (msg->msg_type_action & UNI_MSG_TYPE_ACT_MASK) +
+ UNI_IE_EXT_BIT;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+
+ /*
+ * Save the location of the message length and encode a length
+ * of zero for now. We'll fix the length up at the end.
+ */
+ su.s = 0;
+ rc = usf_byte_mark(usf, &su.sb[sizeof(short)-2], &lp0);
+ if (rc)
+ return(rc);
+ rc = usf_byte_mark(usf, &su.sb[sizeof(short)-1], &lp1);
+ if (rc)
+ return(rc);
+
+ /*
+ * Process information elements
+ */
+ len = 0;
+ for (i=0; i<UNI_MSG_IE_CNT; i++) {
+ ie = msg->msg_ie_vec[i];
+ while (ie) {
+ rc = usf_enc_ie(usf, ie);
+ if (rc)
+ return(rc);
+ len += (ie->ie_length + UNI_IE_HDR_LEN);
+ ie = ie->ie_next;
+ }
+ }
+
+ /*
+ * Fix the message length in the encoded message
+ */
+ su.s = htons((u_short)len);
+ *lp0 = su.sb[sizeof(short)-2];
+ *lp1 = su.sb[sizeof(short)-1];
+
+ return(0);
+}
+
+
+/*
+ * Encode an information element
+ *
+ * Arguments:
+ * usf pointer to a UNISIG formatting structure
+ * msg pointer to a UNISIG message structure
+ * ie pointer to a generic IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_enc_ie(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int i, rc;
+ u_char c;
+ u_char *lp0, *lp1;
+
+ union {
+ short s;
+ u_char sb[sizeof(short)];
+ } su;
+
+ ATM_DEBUG2("usf_enc_ie: usf=0x%x, ie=0x%x\n",
+ (int)usf, (int)ie);
+
+ /*
+ * Encode the IE identifier
+ */
+ rc = usf_byte(usf, &ie->ie_ident);
+ if (rc)
+ return(rc);
+
+ /*
+ * Encode the extended type
+ */
+ c = ((ie->ie_coding & UNI_IE_CODE_MASK) << UNI_IE_CODE_SHIFT) +
+ ((ie->ie_flag & UNI_IE_FLAG_MASK) <<
+ UNI_IE_FLAG_SHIFT) +
+ (ie->ie_action & UNI_IE_ACT_MASK) +
+ UNI_IE_EXT_BIT;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+
+ /*
+ * Mark the current location in the output stream. Encode a
+ * length of zero for now; we'll come back and fix it up at
+ * the end.
+ */
+ su.s = 0;
+ rc = usf_byte_mark(usf, &su.sb[sizeof(short)-2], &lp0);
+ if (rc)
+ return(rc);
+ rc = usf_byte_mark(usf, &su.sb[sizeof(short)-1], &lp1);
+ if (rc)
+ return(rc);
+
+ /*
+ * Look up the information element in the table
+ */
+ for (i=0; (ie->ie_ident != ie_table[i].ident) &&
+ (ie_table[i].encode != NULL); i++) {
+ }
+ if (ie_table[i].encode == NULL) {
+ /*
+ * Unrecognized IE
+ */
+ return(EINVAL);
+ }
+
+ /*
+ * Process the IE by calling the function indicated
+ * in the IE table
+ */
+ rc = ie_table[i].encode(usf, ie);
+ if (rc)
+ return(rc);
+
+ /*
+ * Set the length in the output stream
+ */
+ su.s = htons((u_short)ie->ie_length);
+ *lp0 = su.sb[sizeof(short)-2];
+ *lp1 = su.sb[sizeof(short)-1];
+
+ return(0);
+}
+
+
+/*
+ * Encode an AAL parameters information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to an AAL parms IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_enc_ie_aalp(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int i, rc = 0;
+
+ ATM_DEBUG2("usf_enc_ie_aalp: usf=0x%x, ie=0x%x\n",
+ (int)usf, (int)ie);
+
+ ie->ie_length = 0;
+
+ /*
+ * Encode the AAL type
+ */
+ if (ie->ie_aalp_aal_type == T_ATM_ABSENT)
+ return(0);
+ rc = usf_byte(usf, &ie->ie_aalp_aal_type);
+ if (rc)
+ return(rc);
+
+ /*
+ * Process based on AAL type
+ */
+ switch (ie->ie_aalp_aal_type) {
+ case UNI_IE_AALP_AT_AAL1:
+ rc = usf_enc_ie_ident(usf, ie, ie_aal1_tbl);
+ break;
+ case UNI_IE_AALP_AT_AAL3:
+ if (usf->usf_sig->us_proto == ATM_SIG_UNI30)
+ rc = usf_enc_ie_ident(usf, ie, ie_aal4_tbl_30);
+ else
+ rc = usf_enc_ie_ident(usf, ie, ie_aal4_tbl_31);
+ break;
+ case UNI_IE_AALP_AT_AAL5:
+ if (usf->usf_sig->us_proto == ATM_SIG_UNI30)
+ rc = usf_enc_ie_ident(usf, ie, ie_aal5_tbl_30);
+ else
+ rc = usf_enc_ie_ident(usf, ie, ie_aal5_tbl_31);
+ break;
+ case UNI_IE_AALP_AT_AALU:
+ /*
+ * Encode the user data
+ */
+ i = 0;
+ while (i < sizeof(ie->ie_aalp_user_info)) {
+ rc = usf_byte(usf, &ie->ie_aalp_user_info[i]);
+ if (rc)
+ break;
+ i++;
+ ie->ie_length++;
+ }
+ break;
+ default:
+ return(EINVAL);
+ }
+
+ ie->ie_length++;
+ return(rc);
+}
+
+
+/*
+ * Encode a user cell rate information element
+ *
+ * This routine just encodes the parameters required for best
+ * effort service.
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_enc_ie_clrt(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int rc;
+
+ ATM_DEBUG2("usf_enc_ie_clrt: usf=0x%x, ie=0x%x\n",
+ (int)usf, (int)ie);
+
+#ifdef NOTDEF
+ /*
+ * Encode Peak Cell Rate Forward CLP = 0 + 1
+ */
+ c = UNI_IE_CLRT_FWD_PEAK_01_ID;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ rc = usf_int3(usf, &ie->ie_clrt_fwd_peak_01);
+ if (rc)
+ return(rc);
+
+ /*
+ * Encode Peak Cell Rate Backward CLP = 0 + 1
+ */
+ c = UNI_IE_CLRT_BKWD_PEAK_01_ID;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ rc = usf_int3(usf, &ie->ie_clrt_bkwd_peak_01);
+ if (rc)
+ return(rc);
+
+ /*
+ * Encode Best Effort Flag
+ */
+ c = UNI_IE_CLRT_BEST_EFFORT_ID;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+
+ /*
+ * Set IE length
+ */
+ ie->ie_length = 9;
+#endif
+
+ /*
+ * Encode the user cell rate IE using the table
+ */
+ ie->ie_length = 0;
+ rc = usf_enc_ie_ident(usf, ie, ie_clrt_tbl);
+
+ return(rc);
+}
+
+
+/*
+ * Encode a broadband bearer capability information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_enc_ie_bbcp(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int rc;
+ u_char c;
+
+ ATM_DEBUG2("usf_enc_ie_bbcp: usf=0x%x, ie=0x%x\n",
+ (int)usf, (int)ie);
+
+ ie->ie_length = 0;
+
+ /*
+ * Encode the broadband bearer class
+ */
+ if (ie->ie_bbcp_bearer_class == T_ATM_ABSENT)
+ return(0);
+ c = ie->ie_bbcp_bearer_class & UNI_IE_BBCP_BC_MASK;
+ if (ie->ie_bbcp_bearer_class != UNI_IE_BBCP_BC_BCOB_X)
+ c |= UNI_IE_EXT_BIT;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_length++;
+
+ /*
+ * If the broadband bearer class was X, the next
+ * byte has the traffic type and timing requirements
+ */
+ if (ie->ie_bbcp_bearer_class == UNI_IE_BBCP_BC_BCOB_X) {
+ c = ((ie->ie_bbcp_traffic_type & UNI_IE_BBCP_TT_MASK) <<
+ UNI_IE_BBCP_TT_SHIFT) +
+ (ie->ie_bbcp_timing_req &
+ UNI_IE_BBCP_TR_MASK) +
+ UNI_IE_EXT_BIT;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_length++;
+ }
+
+ /*
+ * Encode the clipping and user plane connection configuration
+ */
+ c = ((ie->ie_bbcp_clipping & UNI_IE_BBCP_SC_MASK) <<
+ UNI_IE_BBCP_SC_SHIFT) +
+ (ie->ie_bbcp_conn_config &
+ UNI_IE_BBCP_CC_MASK) +
+ UNI_IE_EXT_BIT;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_length++;
+
+ return(0);
+}
+
+
+/*
+ * Encode a broadband high layer information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_enc_ie_bhli(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int i, rc;
+ u_int type;
+
+ ATM_DEBUG2("usf_enc_ie_bhli: usf=0x%x, ie=0x%x\n",
+ (int)usf, (int)ie);
+
+ ie->ie_length = 0;
+
+ /*
+ * Encode the high layer information type
+ */
+ if (ie->ie_bhli_type == T_ATM_ABSENT)
+ return(0);
+ type = ie->ie_bhli_type | UNI_IE_EXT_BIT;
+ rc = usf_ext(usf, &type);
+ if (rc)
+ return(rc);
+ ie->ie_length++;
+
+ /*
+ * What comes next depends on the type
+ */
+ switch (ie->ie_bhli_type) {
+ case UNI_IE_BHLI_TYPE_ISO:
+ case UNI_IE_BHLI_TYPE_USER:
+ /*
+ * ISO or user-specified parameters -- take the
+ * length of information from the IE length
+ */
+ for (i=0; i<ie->ie_length-1; i++) {
+ rc = usf_byte(usf, &ie->ie_bhli_info[i]);
+ if (rc)
+ return(rc);
+ ie->ie_length++;
+ }
+ break;
+ case UNI_IE_BHLI_TYPE_HLP:
+ /*
+ * Make sure the IE is long enough for the high
+ * layer profile information, then get it
+ */
+ if (usf->usf_sig->us_proto != ATM_SIG_UNI30)
+ return (EINVAL);
+ for (i=0; i<UNI_IE_BHLI_HLP_LEN; i++) {
+ rc = usf_byte(usf, &ie->ie_bhli_info[i]);
+ if (rc)
+ return(rc);
+ ie->ie_length++;
+ }
+ break;
+ case UNI_IE_BHLI_TYPE_VSA:
+ /*
+ * Make sure the IE is long enough for the vendor-
+ * specific application information, then get it
+ */
+ for (i=0; i<UNI_IE_BHLI_VSA_LEN; i++) {
+ rc = usf_byte(usf, &ie->ie_bhli_info[i]);
+ if (rc)
+ return(rc);
+ ie->ie_length++;
+ }
+ break;
+ default:
+ return(EINVAL);
+ }
+
+ return(0);
+}
+
+
+/*
+ * Encode a broadband low layer information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_enc_ie_blli(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ u_char c;
+ int rc;
+ u_int ipi;
+
+ ATM_DEBUG2("usf_enc_ie_blli: usf=0x%x, ie=0x%x\n",
+ (int)usf, (int)ie);
+
+ ie->ie_length = 0;
+
+ /*
+ * Encode paramteters for whichever protocol layers the
+ * user specified
+ */
+
+ /*
+ * Layer 1 information
+ */
+ if (ie->ie_blli_l1_id && ie->ie_blli_l1_id != T_ATM_ABSENT) {
+ c = (UNI_IE_BLLI_L1_ID << UNI_IE_BLLI_LID_SHIFT) +
+ (ie->ie_blli_l1_id &
+ UNI_IE_BLLI_LP_MASK) +
+ UNI_IE_EXT_BIT;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_length++;
+ }
+
+ /*
+ * Layer 2 information
+ */
+ if (ie->ie_blli_l2_id && ie->ie_blli_l2_id != T_ATM_ABSENT) {
+ c = (UNI_IE_BLLI_L2_ID << UNI_IE_BLLI_LID_SHIFT) +
+ (ie->ie_blli_l2_id &
+ UNI_IE_BLLI_LP_MASK);
+
+ switch (ie->ie_blli_l2_id) {
+ case UNI_IE_BLLI_L2P_X25L:
+ case UNI_IE_BLLI_L2P_X25M:
+ case UNI_IE_BLLI_L2P_HDLC1:
+ case UNI_IE_BLLI_L2P_HDLC2:
+ case UNI_IE_BLLI_L2P_HDLC3:
+ case UNI_IE_BLLI_L2P_Q922:
+ case UNI_IE_BLLI_L2P_ISO7776:
+ /*
+ * Write the Layer 2 type
+ */
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_length++;
+
+ /*
+ * Encode the Layer 2 mode
+ */
+ if (ie->ie_blli_l2_mode) {
+ c = (ie->ie_blli_l2_mode &
+ UNI_IE_BLLI_L2MODE_MASK) <<
+ UNI_IE_BLLI_L2MODE_SHIFT;
+ if (!ie->ie_blli_l2_window)
+ c |= UNI_IE_EXT_BIT;
+
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_length++;
+ }
+
+ /*
+ * Encode the Layer 2 window size
+ */
+ if (ie->ie_blli_l2_window) {
+ c = (ie->ie_blli_l2_window &
+ UNI_IE_EXT_MASK) +
+ UNI_IE_EXT_BIT;
+
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_length++;
+ }
+ break;
+ case UNI_IE_BLLI_L2P_USER:
+ /*
+ * Write the Layer 2 type
+ */
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_length++;
+
+ /*
+ * Encode the user-specified layer 2 info
+ */
+ c = (ie->ie_blli_l2_user_proto &
+ UNI_IE_EXT_MASK) +
+ UNI_IE_EXT_BIT;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_length++;
+ break;
+ default:
+ /*
+ * Write the Layer 2 type
+ */
+ c |= UNI_IE_EXT_BIT;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_length++;
+ break;
+ }
+ }
+
+ /*
+ * Layer 3 information
+ */
+ if (ie->ie_blli_l3_id && ie->ie_blli_l3_id != T_ATM_ABSENT) {
+ /*
+ * Encode the layer 3 protocol ID
+ */
+ c = (UNI_IE_BLLI_L3_ID << UNI_IE_BLLI_LID_SHIFT) +
+ (ie->ie_blli_l3_id &
+ UNI_IE_BLLI_LP_MASK);
+
+ /*
+ * Process other fields based on protocol ID
+ */
+ switch(ie->ie_blli_l3_id) {
+ case UNI_IE_BLLI_L3P_X25:
+ case UNI_IE_BLLI_L3P_ISO8208:
+ case UNI_IE_BLLI_L3P_ISO8878:
+ /*
+ * Write the protocol ID
+ */
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_length++;
+
+ if (ie->ie_blli_l3_mode ||
+ ie->ie_blli_l3_packet_size ||
+ ie->ie_blli_l3_window) {
+ c = (ie->ie_blli_l3_mode &
+ UNI_IE_BLLI_L3MODE_MASK) <<
+ UNI_IE_BLLI_L3MODE_SHIFT;
+ if (!ie->ie_blli_l3_packet_size &&
+ !ie->ie_blli_l3_window)
+ c |= UNI_IE_EXT_BIT;
+
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_length++;
+ }
+
+ if (ie->ie_blli_l3_packet_size ||
+ ie->ie_blli_l3_window) {
+ c = ie->ie_blli_l3_packet_size &
+ UNI_IE_BLLI_L3PS_MASK;
+ if (!ie->ie_blli_l3_window)
+ c |= UNI_IE_EXT_BIT;
+
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_length++;
+ }
+
+ if (ie->ie_blli_l3_window) {
+ c = (ie->ie_blli_l3_window &
+ UNI_IE_EXT_MASK) +
+ UNI_IE_EXT_BIT;
+
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_length++;
+ }
+ break;
+ case UNI_IE_BLLI_L3P_USER:
+ /*
+ * Write the protocol ID
+ */
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_length++;
+
+ /*
+ * Encode the user-specified protocol info
+ */
+ c = (ie->ie_blli_l3_user_proto &
+ UNI_IE_EXT_MASK) +
+ UNI_IE_EXT_BIT;
+
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_length++;
+ break;
+ case UNI_IE_BLLI_L3P_ISO9577:
+ /*
+ * Write the protocol ID
+ */
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_length++;
+
+ /*
+ * Encode the IPI
+ */
+ ipi = ie->ie_blli_l3_ipi <<
+ UNI_IE_BLLI_L3IPI_SHIFT;
+ rc = usf_ext(usf, &ipi);
+ if (rc)
+ return(rc);
+ ie->ie_length += 2;
+
+ if (ie->ie_blli_l3_ipi ==
+ UNI_IE_BLLI_L3IPI_SNAP) {
+ c = UNI_IE_EXT_BIT;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+
+ rc = usf_byte(usf,
+ &ie->ie_blli_l3_oui[0]);
+ if (rc)
+ return(rc);
+
+ rc = usf_byte(usf,
+ &ie->ie_blli_l3_oui[1]);
+ if (rc)
+ return(rc);
+
+ rc = usf_byte(usf,
+ &ie->ie_blli_l3_oui[2]);
+ if (rc)
+ return(rc);
+
+ rc = usf_byte(usf,
+ &ie->ie_blli_l3_pid[0]);
+ if (rc)
+ return(rc);
+
+ rc = usf_byte(usf,
+ &ie->ie_blli_l3_pid[1]);
+ if (rc)
+ return(rc);
+
+ ie->ie_length += 6;
+ }
+ break;
+ default:
+ /*
+ * Write the layer 3 protocol ID
+ */
+ c |= UNI_IE_EXT_BIT;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_length++;
+ break;
+ }
+ }
+
+ return(0);
+}
+
+
+/*
+ * Encode a call state information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_enc_ie_clst(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int rc;
+ u_char c;
+
+ ATM_DEBUG2("usf_enc_ie_clst: usf=0x%x, ie=0x%x\n",
+ (int)usf, (int)ie);
+
+ c = ie->ie_clst_state & UNI_IE_CLST_STATE_MASK;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_length = 1;
+
+ return(0);
+}
+
+
+/*
+ * Encode a called party number information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_enc_ie_cdad(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ u_char c;
+ int rc;
+
+ ATM_DEBUG2("usf_enc_ie_cdad: usf=0x%x, ie=0x%x\n",
+ (int)usf, (int)ie);
+
+ /*
+ * Encode the numbering plan
+ */
+ switch(ie->ie_cdad_addr.address_format) {
+ case T_ATM_E164_ADDR:
+ c = UNI_IE_CDAD_PLAN_E164 +
+ (UNI_IE_CDAD_TYPE_INTL
+ << UNI_IE_CDAD_TYPE_SHIFT);
+ ie->ie_length = sizeof(Atm_addr_e164) + 1;
+ break;
+ case T_ATM_ENDSYS_ADDR:
+ c = UNI_IE_CDAD_PLAN_NSAP +
+ (UNI_IE_CDAD_TYPE_UNK
+ << UNI_IE_CDAD_TYPE_SHIFT);
+ ie->ie_length = sizeof(Atm_addr_nsap) + 1;
+ break;
+ default:
+ return(EINVAL);
+ }
+ c |= UNI_IE_EXT_BIT;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+
+ /*
+ * Encode the ATM address
+ */
+ rc = usf_enc_atm_addr(usf, &ie->ie_cdad_addr);
+
+ return(rc);
+}
+
+
+/*
+ * Encode a called party subaddress information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_enc_ie_cdsa(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ u_char c;
+ int rc;
+
+ /*
+ * Encode the subaddress type
+ */
+ switch(ie->ie_cdsa_addr.address_format) {
+ case T_ATM_ENDSYS_ADDR:
+ c = UNI_IE_CDSA_TYPE_AESA << UNI_IE_CDSA_TYPE_SHIFT;
+ ie->ie_length = sizeof(Atm_addr_nsap) + 1;
+ break;
+ default:
+ return(EINVAL);
+ }
+ c |= UNI_IE_EXT_BIT;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+
+ /*
+ * Encode the ATM address
+ */
+ rc = usf_enc_atm_addr(usf, &ie->ie_cdsa_addr);
+
+ return(rc);
+}
+
+
+/*
+ * Encode a calling party number information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_enc_ie_cgad(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ u_char c;
+ int rc;
+
+ ATM_DEBUG2("usf_enc_ie_cgad: usf=0x%x, ie=0x%x\n",
+ (int)usf, (int)ie);
+
+ /*
+ * Encode the numbering plan
+ */
+ switch(ie->ie_cgad_addr.address_format) {
+ case T_ATM_E164_ADDR:
+ c = UNI_IE_CGAD_PLAN_E164 +
+ (UNI_IE_CGAD_TYPE_INTL
+ << UNI_IE_CGAD_TYPE_SHIFT) +
+ UNI_IE_EXT_BIT;
+ ie->ie_length = sizeof(Atm_addr_e164) + 1;
+ break;
+ case T_ATM_ENDSYS_ADDR:
+ c = UNI_IE_CGAD_PLAN_NSAP +
+ (UNI_IE_CGAD_TYPE_UNK
+ << UNI_IE_CGAD_TYPE_SHIFT) +
+ UNI_IE_EXT_BIT;
+ ie->ie_length = sizeof(Atm_addr_nsap) + 1;
+ break;
+ default:
+ return(EINVAL);
+ }
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+
+ /*
+ * Encode the presentation and screening indicators
+ */
+#ifdef NOTDEF
+ c = ((ie->ie_cgad_pres_ind & UNI_IE_CGAD_PRES_MASK)
+ << UNI_IE_CGAD_PRES_SHIFT) +
+ (ie->ie_cgad_screen_ind &
+ UNI_IE_CGAD_SCR_MASK) +
+ UNI_IE_EXT_BIT;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+#endif
+
+
+ /*
+ * Encode the ATM address
+ */
+ rc = usf_enc_atm_addr(usf, &ie->ie_cgad_addr);
+
+ return(rc);
+}
+
+
+/*
+ * Encode a calling party subaddress information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_enc_ie_cgsa(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ u_char c;
+ int rc;
+
+ /*
+ * Encode the subaddress type
+ */
+ switch(ie->ie_cgsa_addr.address_format) {
+ case T_ATM_ENDSYS_ADDR:
+ c = UNI_IE_CGSA_TYPE_AESA << UNI_IE_CGSA_TYPE_SHIFT;
+ ie->ie_length = sizeof(Atm_addr_nsap) + 1;
+ break;
+ default:
+ return(EINVAL);
+ }
+ c |= UNI_IE_EXT_BIT;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+
+ /*
+ * Encode the ATM address
+ */
+ rc = usf_enc_atm_addr(usf, &ie->ie_cgsa_addr);
+
+ return(rc);
+}
+
+
+/*
+ * Encode a cause information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_enc_ie_caus(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int i, rc;
+ u_char c;
+
+ ATM_DEBUG2("usf_enc_ie_caus: usf=0x%x, ie=0x%x\n",
+ (int)usf, (int)ie);
+
+ ie->ie_length = 0;
+
+ /*
+ * Encode the cause location
+ */
+ c = (ie->ie_caus_loc & UNI_IE_CAUS_LOC_MASK) | UNI_IE_EXT_BIT;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_length++;
+
+ /*
+ * Encode the cause value
+ */
+ c = ie->ie_caus_cause | UNI_IE_EXT_BIT;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_length++;
+
+ /*
+ * Encode any included diagnostics
+ */
+ for (i = 0; i < ie->ie_caus_diag_len &&
+ i < sizeof(ie->ie_caus_diagnostic);
+ i++) {
+ rc = usf_byte(usf, &ie->ie_caus_diagnostic[i]);
+ if (rc)
+ return(rc);
+ ie->ie_length++;
+ }
+
+ return(0);
+}
+
+
+/*
+ * Encode a conection identifier information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_enc_ie_cnid(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int rc;
+ u_char c;
+
+ ATM_DEBUG2("usf_enc_ie_cnid: usf=0x%x, ie=0x%x\n",
+ (int)usf, (int)ie);
+
+ c = ((ie->ie_cnid_vp_sig & UNI_IE_CNID_VPSIG_MASK)
+ << UNI_IE_CNID_VPSIG_SHIFT) +
+ (ie->ie_cnid_pref_excl & UNI_IE_CNID_PREX_MASK) +
+ UNI_IE_EXT_BIT;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+
+ rc = usf_short(usf, &ie->ie_cnid_vpci);
+ if (rc)
+ return(rc);
+ rc = usf_short(usf, &ie->ie_cnid_vci);
+ if (rc)
+ return(rc);
+
+ ie->ie_length = 5;
+ return(0);
+}
+
+
+/*
+ * Encode a quality of service parameters information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_enc_ie_qosp(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int rc;
+
+ ATM_DEBUG2("usf_enc_ie_qosp: usf=0x%x, ie=0x%x\n",
+ (int)usf, (int)ie);
+
+ /*
+ * Encode forward QoS class
+ */
+ if (ie->ie_qosp_fwd_class == T_ATM_ABSENT ||
+ ie->ie_qosp_bkwd_class == T_ATM_ABSENT)
+ return(0);
+ rc = usf_byte(usf, &ie->ie_qosp_fwd_class);
+ if (rc)
+ return(rc);
+
+ /*
+ * Encode backward QoS class
+ */
+ rc = usf_byte(usf, &ie->ie_qosp_bkwd_class);
+
+ ie->ie_length = 2;
+ return(rc);
+}
+
+
+/*
+ * Encode a broadband repeat indicator information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_enc_ie_brpi(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int rc;
+ u_char c;
+
+ ATM_DEBUG2("usf_enc_ie_brpi: usf=0x%x, ie=0x%x\n",
+ (int)usf, (int)ie);
+
+ /*
+ * Encode the repeat indicator
+ */
+ c = ie->ie_brpi_ind + UNI_IE_EXT_BIT;
+ rc = usf_byte(usf, &c);
+
+ return(rc);
+}
+
+
+/*
+ * Encode a restart indicator information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_enc_ie_rsti(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int rc;
+ u_char c;
+
+ ATM_DEBUG2("usf_enc_ie_rsti: usf=0x%x, ie=0x%x\n",
+ (int)usf, (int)ie);
+
+ /*
+ * Encode the restart class
+ */
+ c = (ie->ie_rsti_class & UNI_IE_RSTI_CLASS_MASK) |
+ UNI_IE_EXT_BIT;
+ rc = usf_byte(usf, &c);
+ ie->ie_length = 1;
+
+ return(rc);
+}
+
+
+/*
+ * Encode a broadband sending complete information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a broadband sending complete IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_enc_ie_bsdc(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int rc;
+ u_char c;
+
+ ATM_DEBUG2("usf_enc_ie_bsdc: usf=0x%x, ie=0x%x\n",
+ (int)usf, (int)ie);
+
+ /*
+ * Encode the sending complete indicator
+ */
+ c = UNI_IE_BSDC_IND | UNI_IE_EXT_BIT;
+ rc = usf_byte(usf, &c);
+ ie->ie_length = 1;
+
+ return(rc);
+}
+
+
+/*
+ * Encode a transit network selection information element
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a transit network selection rate IE structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_enc_ie_trnt(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ int i, rc;
+ u_char c;
+
+ ATM_DEBUG2("usf_enc_ie_trnt: usf=0x%x, ie=0x%x\n",
+ (int)usf, (int)ie);
+
+ /*
+ * Encode the sending complete indicator
+ */
+ c = ((ie->ie_trnt_id_type & UNI_IE_TRNT_IDT_MASK) <<
+ UNI_IE_TRNT_IDT_SHIFT) +
+ (ie->ie_trnt_id_plan & UNI_IE_TRNT_IDP_MASK) +
+ UNI_IE_EXT_BIT;
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ ie->ie_length = 1;
+
+ /*
+ * Encode the network identification
+ */
+ for (i=0; i<ie->ie_trnt_id_len; i++) {
+ rc = usf_byte(usf, &ie->ie_trnt_id[i]);
+ if (rc)
+ return(rc);
+ ie->ie_length++;
+ }
+
+ return(rc);
+}
+
+
+/*
+ * Encode an unsupported IE type
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to an IE structure
+ *
+ * Returns:
+ * 0 success
+ *
+ */
+static int
+usf_enc_ie_uimp(usf, ie)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+{
+ return(0);
+}
+
+
+/*
+ * Encode an information element using field identifiers
+ *
+ * The AAL parameters and ATM user cell rate IEs are formatted
+ * with a one-byte identifier preceeding each field. The routine
+ * encodes these IEs by using a table which relates the field
+ * identifiers with the fields in the appropriate IE structure.
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * ie pointer to a cell rate IE structure
+ * tbl pointer to an IE decoding table
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_enc_ie_ident(usf, ie, tbl)
+ struct usfmt *usf;
+ struct ie_generic *ie;
+ struct ie_decode_tbl *tbl;
+{
+ int i, len, rc;
+ char *cp;
+ u_int8_t cv;
+ u_int16_t sv;
+ u_int32_t iv;
+
+ ATM_DEBUG3("usf_enc_ie_ident: usf=0x%x, ie=0x%x, tbl=0x%x\n",
+ (int)usf, (int)ie, (int)tbl);
+
+ /*
+ * Scan through the IE table
+ */
+ len = 0;
+ for (i=0; tbl[i].ident; i++) {
+ /*
+ * Check whether to send the field
+ */
+ cp = (char *) ((int)ie + tbl[i].f_offs);
+ if (tbl[i].len == 0) {
+ if ((*cp == T_NO || *cp == T_ATM_ABSENT))
+ continue;
+ } else {
+ switch (tbl[i].f_size) {
+ case 1:
+ if (*(int8_t *)cp == T_ATM_ABSENT)
+ continue;
+ break;
+ case 2:
+ if (*(int16_t *)cp == T_ATM_ABSENT)
+ continue;
+ break;
+ case 4:
+ if (*(int32_t *)cp == T_ATM_ABSENT)
+ continue;
+ break;
+ default:
+badtbl:
+ log(LOG_ERR,
+ "uni encode: id=%d,len=%d,off=%d,size=%d\n",
+ tbl[i].ident, tbl[i].len,
+ tbl[i].f_offs, tbl[i].f_size);
+ return (EFAULT);
+ }
+ }
+
+ /*
+ * Encode the field identifier
+ */
+ rc = usf_byte(usf, &tbl[i].ident);
+ if (rc)
+ return(rc);
+ len++;
+
+ /*
+ * Encode the field value
+ */
+ switch (tbl[i].len) {
+ case 0:
+ break;
+ case 1:
+ switch (tbl[i].f_size) {
+ case 1:
+ cv = *(u_int8_t *)cp;
+ break;
+ case 2:
+ cv = *(u_int16_t *)cp;
+ break;
+ case 4:
+ cv = *(u_int32_t *)cp;
+ break;
+ default:
+ goto badtbl;
+ }
+ rc = usf_byte(usf, &cv);
+ break;
+
+ case 2:
+ switch (tbl[i].f_size) {
+ case 2:
+ sv = *(u_int16_t *)cp;
+ break;
+ case 4:
+ sv = *(u_int32_t *)cp;
+ break;
+ default:
+ goto badtbl;
+ }
+ rc = usf_short(usf, &sv);
+ break;
+
+ case 3:
+ switch (tbl[i].f_size) {
+ case 4:
+ iv = *(u_int32_t *)cp;
+ break;
+ default:
+ goto badtbl;
+ }
+ rc = usf_int3(usf, &iv);
+ break;
+
+ case 4:
+ switch (tbl[i].f_size) {
+ case 4:
+ iv = *(u_int32_t *)cp;
+ break;
+ default:
+ goto badtbl;
+ }
+ rc = usf_int(usf, &iv);
+ break;
+
+ default:
+ goto badtbl;
+ }
+
+ len += tbl[i].len;
+
+ if (rc)
+ return(rc);
+ }
+
+ ie->ie_length = len;
+ return(0);
+}
+
+
+/*
+ * Encode an ATM address
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * addr pointer to an ATM address structure. The address
+ * type must already be set correctly.
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+usf_enc_atm_addr(usf, addr)
+ struct usfmt *usf;
+ Atm_addr *addr;
+{
+ int len, rc;
+ u_char *cp;
+
+ /*
+ * Check the address type
+ */
+ switch (addr->address_format) {
+ case T_ATM_E164_ADDR:
+ cp = (u_char *) addr->address;
+ len = sizeof(Atm_addr_e164);
+ break;
+ case T_ATM_ENDSYS_ADDR:
+ cp = (u_char *) addr->address;
+ len = sizeof(Atm_addr_nsap);
+ break;
+ default:
+ return(EINVAL);
+ }
+
+ /*
+ * Get the address bytes
+ */
+ while (len) {
+ rc = usf_byte(usf, cp);
+ if (rc)
+ return(rc);
+ len--;
+ cp++;
+ }
+
+ return(0);
+}
diff --git a/sys/netatm/uni/unisig_if.c b/sys/netatm/uni/unisig_if.c
new file mode 100644
index 0000000..784b6c5
--- /dev/null
+++ b/sys/netatm/uni/unisig_if.c
@@ -0,0 +1,1012 @@
+/*
+ *
+ * ===================================
+ * 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: unisig_if.c,v 1.12 1998/07/30 22:36:57 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI 3.0/3.1 Signalling Manager
+ * ----------------------------------------
+ *
+ * System interface module
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: unisig_if.c,v 1.12 1998/07/30 22:36:57 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/ipatm/ipatm_var.h>
+#include <netatm/ipatm/ipatm_serv.h>
+#include <netatm/uni/uniip_var.h>
+
+#include <netatm/uni/uni.h>
+#include <netatm/uni/unisig.h>
+#include <netatm/uni/unisig_var.h>
+#include <netatm/uni/unisig_msg.h>
+
+
+/*
+ * Global variables
+ */
+struct sp_info unisig_vcpool = {
+ "unisig vcc pool", /* si_name */
+ sizeof(struct unisig_vccb), /* si_blksiz */
+ 10, /* si_blkcnt */
+ 50 /* si_maxallow */
+};
+
+struct sp_info unisig_msgpool = {
+ "unisig message pool", /* si_name */
+ sizeof(struct unisig_msg), /* si_blksiz */
+ 10, /* si_blkcnt */
+ 50 /* si_maxallow */
+};
+
+struct sp_info unisig_iepool = {
+ "unisig ie pool", /* si_name */
+ sizeof(struct ie_generic), /* si_blksiz */
+ 10, /* si_blkcnt */
+ 50 /* si_maxallow */
+};
+
+
+/*
+ * Local functions
+ */
+static int unisig_attach __P((struct sigmgr *, struct atm_pif *));
+static int unisig_detach __P((struct atm_pif *));
+static int unisig_setup __P((Atm_connvc *, int *));
+static int unisig_release __P((struct vccb *, int *));
+static int unisig_accept __P((struct vccb *, int *));
+static int unisig_reject __P((struct vccb *, int *));
+static int unisig_abort __P((struct vccb *));
+static int unisig_ioctl __P((int, caddr_t, caddr_t));
+
+
+/*
+ * Local variables
+ */
+static struct sigmgr unisig_mgr30 = {
+ NULL,
+ ATM_SIG_UNI30,
+ NULL,
+ unisig_attach,
+ unisig_detach,
+ unisig_setup,
+ unisig_accept,
+ unisig_reject,
+ unisig_release,
+ unisig_free,
+ unisig_ioctl
+};
+
+static struct sigmgr unisig_mgr31 = {
+ NULL,
+ ATM_SIG_UNI31,
+ NULL,
+ unisig_attach,
+ unisig_detach,
+ unisig_setup,
+ unisig_accept,
+ unisig_reject,
+ unisig_release,
+ unisig_free,
+ unisig_ioctl
+};
+
+
+/*
+ * Initialize UNISIG processing
+ *
+ * This will be called during module loading. We'll just register
+ * the UNISIG protocol descriptor and wait for a UNISIG ATM interface
+ * to come online.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 startup was successful
+ * errno startup failed - reason indicated
+ *
+ */
+int
+unisig_start()
+{
+ int err = 0;
+
+ /*
+ * Verify software version
+ */
+ if (atm_version != ATM_VERSION) {
+ log(LOG_ERR, "version mismatch: unisig=%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);
+ }
+
+ /*
+ * Register ourselves with system
+ */
+ err = atm_sigmgr_register(&unisig_mgr30);
+ if (err)
+ goto done;
+
+ err = atm_sigmgr_register(&unisig_mgr31);
+
+done:
+ return (err);
+}
+
+
+/*
+ * Halt UNISIG processing
+ *
+ * This should be called just prior to unloading the module from
+ * memory. All UNISIG interfaces must be deregistered before the
+ * protocol can be shutdown.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 startup was successful
+ * errno startup failed - reason indicated
+ *
+ */
+int
+unisig_stop()
+{
+ int err = 0;
+ int s = splnet();
+
+
+ /*
+ * Any protocol instances still registered?
+ */
+ if ((unisig_mgr30.sm_prinst != NULL) ||
+ (unisig_mgr31.sm_prinst != NULL)) {
+
+ /* Yes, can't stop now */
+ err = EBUSY;
+ goto done;
+ }
+
+ /*
+ * De-register from system
+ */
+ (void) atm_sigmgr_deregister(&unisig_mgr30);
+ (void) atm_sigmgr_deregister(&unisig_mgr31);
+
+ /*
+ * Free up our storage pools
+ */
+ atm_release_pool(&unisig_vcpool);
+ atm_release_pool(&unisig_msgpool);
+ atm_release_pool(&unisig_iepool);
+
+done:
+ (void) splx(s);
+ return (err);
+}
+
+
+/*
+ * Attach a UNISIG-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 UNISIG-controlled interfaces. A new UNISIG 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 UNISIG signalling manager control block
+ * pip pointer to ATM physical interface control block
+ *
+ * Returns:
+ * 0 attach successful
+ * errno attach failed - reason indicated
+ *
+ */
+static int
+unisig_attach(smp, pip)
+ struct sigmgr *smp;
+ struct atm_pif *pip;
+{
+ int err = 0, s;
+ struct unisig *usp = NULL;
+
+ ATM_DEBUG2("unisig_attach: smp=%x, pip=%x\n", smp, pip);
+
+ /*
+ * Allocate UNISIG protocol instance control block
+ */
+ usp = (struct unisig *)
+ KM_ALLOC(sizeof(struct unisig), M_DEVBUF, M_NOWAIT);
+ if (usp == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+ KM_ZERO(usp, sizeof(struct unisig));
+
+ /*
+ * Set state in UNISIG protocol instance control block
+ */
+ usp->us_state = UNISIG_NULL;
+ usp->us_proto = smp->sm_proto;
+
+ /*
+ * Set initial call reference allocation value
+ */
+ usp->us_cref = 1;
+
+ /*
+ * Link instance into manager's chain
+ */
+ LINK2TAIL((struct siginst *)usp, struct siginst, smp->sm_prinst,
+ si_next);
+
+ /*
+ * Link in interface
+ */
+ usp->us_pif = pip;
+ s = splimp();
+ pip->pif_sigmgr = smp;
+ pip->pif_siginst = (struct siginst *) usp;
+ (void) splx(s);
+
+ /*
+ * Clear our ATM address. The address will be set by user
+ * command or by registration via ILMI.
+ */
+ usp->us_addr.address_format = T_ATM_ABSENT;
+ usp->us_addr.address_length = 0;
+ usp->us_subaddr.address_format = T_ATM_ABSENT;
+ usp->us_subaddr.address_length = 0;
+
+ /*
+ * Set pointer to IP
+ */
+ usp->us_ipserv = &uniip_ipserv;
+
+ /*
+ * Kick-start the UNISIG protocol
+ */
+ UNISIG_TIMER(usp, 0);
+
+ /*
+ * Log the fact that we've attached
+ */
+ log(LOG_INFO, "unisig: attached to interface %s%d\n",
+ pip->pif_name, pip->pif_unit);
+
+done:
+ /*
+ * Reset our work if attach fails
+ */
+ if (err) {
+ if (usp) {
+ UNISIG_CANCEL(usp);
+ UNLINK((struct siginst *)usp, struct siginst,
+ smp->sm_prinst, si_next);
+ KM_FREE(usp, sizeof(struct unisig), M_DEVBUF);
+ }
+ s = splimp();
+ pip->pif_sigmgr = NULL;
+ pip->pif_siginst = NULL;
+ (void) splx(s);
+ }
+
+ return (err);
+}
+
+
+/*
+ * Detach a UNISIG-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 UNISIG-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
+unisig_detach(pip)
+ struct atm_pif *pip;
+{
+ struct unisig *usp;
+ int err;
+
+ ATM_DEBUG1("unisig_detach: pip=0x%x\n", pip);
+
+ /*
+ * Get UNISIG protocol instance
+ */
+ usp = (struct unisig *)pip->pif_siginst;
+
+ /*
+ * Return an error if we're already detaching
+ */
+ if (usp->us_state == UNISIG_DETACH) {
+ return(EALREADY);
+ }
+
+ /*
+ * Pass the detach event to the signalling manager
+ * state machine
+ */
+ err = unisig_sigmgr_state(usp, UNISIG_SIGMGR_DETACH,
+ (KBuffer *)0);
+
+ /*
+ * Log the fact that we've detached
+ */
+ if (!err)
+ log(LOG_INFO, "unisig: detached from interface %s%d\n",
+ pip->pif_name, pip->pif_unit);
+
+ return (0);
+}
+
+
+/*
+ * Open a UNISIG ATM Connection
+ *
+ * All service user requests to open a VC connection (via
+ * atm_open_connection) over an ATM interface attached to the UNISIG
+ * 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
+unisig_setup(cvp, errp)
+ Atm_connvc *cvp;
+ int *errp;
+{
+ struct atm_pif *pip = cvp->cvc_attr.nif->nif_pif;
+ struct unisig *usp = (struct unisig *)pip->pif_siginst;
+ int rc = 0;
+
+ ATM_DEBUG1("unisig_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 = unisig_open_vcc(usp, cvp);
+ rc = (*errp ? CALL_FAILED : CALL_CONNECTED);
+ break;
+
+ case T_ATM_ENDSYS_ADDR:
+ case T_ATM_E164_ADDR:
+
+ /*
+ * Create an SVC
+ */
+ *errp = unisig_open_vcc(usp, cvp);
+ rc = (*errp ? CALL_FAILED : CALL_PROCEEDING);
+ break;
+
+ default:
+ *errp = EPROTONOSUPPORT;
+ rc = CALL_FAILED;
+ }
+
+ return (rc);
+}
+
+
+/*
+ * Close a UNISIG 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 UNISIG 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
+unisig_release(vcp, errp)
+ struct vccb *vcp;
+ int *errp;
+{
+ int rc = 0;
+ struct atm_pif *pip = vcp->vc_pif;
+ struct unisig *usp = (struct unisig *)pip->pif_siginst;
+
+ ATM_DEBUG1("unisig_release: vcp=0x%x\n", vcp);
+
+ /*
+ * Initialize returned error code
+ */
+ *errp = 0;
+
+ /*
+ * Validate the connection type (PVC or SVC)
+ */
+ if (!(vcp->vc_type & (VCC_PVC | VCC_SVC))) {
+ *errp = EPROTONOSUPPORT;
+ return(CALL_FAILED);
+ }
+
+ /*
+ * Close the VCCB
+ */
+ *errp = unisig_close_vcc(usp, (struct unisig_vccb *)vcp);
+
+ /*
+ * Set the return code
+ */
+ if (*errp) {
+ rc = CALL_FAILED;
+ } else if (vcp->vc_sstate == UNI_NULL ||
+ vcp->vc_sstate == UNI_FREE) {
+ rc = CALL_CLEARED;
+ } else {
+ rc = CALL_PROCEEDING;
+ }
+
+ return (rc);
+}
+
+
+/*
+ * Accept a UNISIG 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
+unisig_accept(vcp, errp)
+ struct vccb *vcp;
+ int *errp;
+{
+ struct unisig_vccb *uvp = (struct unisig_vccb *)vcp;
+ struct atm_pif *pip = uvp->uv_pif;
+ struct unisig *usp = (struct unisig *)pip->pif_siginst;
+
+ ATM_DEBUG1("unisig_accept: vcp=0x%x\n", vcp);
+
+ /*
+ * Initialize the returned error code
+ */
+ *errp = 0;
+
+ /*
+ * Return an error if we're detaching
+ */
+ if (usp->us_state == UNISIG_DETACH) {
+ *errp = ENETDOWN;
+ goto free;
+ }
+
+ /*
+ * Return an error if we lost the connection
+ */
+ if (uvp->uv_sstate == UNI_FREE) {
+ *errp = ENETDOWN;
+ goto free;
+ }
+
+ /*
+ * Pass the acceptance to the VC state machine
+ */
+ *errp = unisig_vc_state(usp, uvp, UNI_VC_ACCEPT_CALL,
+ (struct unisig_msg *) 0);
+ if (*errp)
+ goto failed;
+
+ return(CALL_PROCEEDING);
+
+failed:
+ /*
+ * On error, free the VCCB and return CALL_FAILED
+ */
+
+free:
+ uvp->uv_sstate = UNI_FREE;
+ uvp->uv_ustate = VCCU_CLOSED;
+ DEQUEUE(uvp, struct unisig_vccb, uv_sigelem, usp->us_vccq);
+ unisig_free((struct vccb *)uvp);
+
+ return(CALL_FAILED);
+}
+
+
+/*
+ * Reject a UNISIG 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:
+ * uvp 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
+unisig_reject(vcp, errp)
+ struct vccb *vcp;
+ int *errp;
+{
+ struct unisig_vccb *uvp = (struct unisig_vccb *)vcp;
+ struct atm_pif *pip = uvp->uv_pif;
+ struct unisig *usp = (struct unisig *)pip->pif_siginst;
+
+ ATM_DEBUG1("unisig_reject: uvp=0x%x\n", uvp);
+
+ /*
+ * Initialize the returned error code
+ */
+ *errp = 0;
+
+
+ /*
+ * Return an error if we're detaching
+ */
+ if (usp->us_state == UNISIG_DETACH) {
+ *errp = ENETDOWN;
+ goto failed;
+ }
+
+ /*
+ * Call the VC state machine
+ */
+ *errp = unisig_vc_state(usp, uvp, UNI_VC_REJECT_CALL,
+ (struct unisig_msg *) 0);
+ if (*errp)
+ goto failed;
+
+ return(CALL_CLEARED);
+
+failed:
+ /*
+ * On error, free the VCCB and return CALL_FAILED
+ */
+ uvp->uv_sstate = UNI_FREE;
+ uvp->uv_ustate = VCCU_CLOSED;
+ DEQUEUE(uvp, struct unisig_vccb, uv_sigelem, usp->us_vccq);
+ (void) unisig_free((struct vccb *)uvp);
+ return(CALL_FAILED);
+}
+
+
+/*
+ * Abort a UNISIG 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 UNISIG 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 successful
+ * errno connection release failed - reason indicated
+ *
+ */
+static int
+unisig_abort(vcp)
+ struct vccb *vcp;
+{
+
+ ATM_DEBUG1("unisig_abort: vcp=0x%x\n", (int)vcp);
+
+ /*
+ * Only abort once
+ */
+ if (vcp->vc_ustate == VCCU_ABORT) {
+ return (EALREADY);
+ }
+
+ /*
+ * Cancel any timer that might be running
+ */
+ UNISIG_VC_CANCEL(vcp);
+
+ /*
+ * Set immediate timer to schedule connection termination
+ */
+ vcp->vc_ustate = VCCU_ABORT;
+ UNISIG_VC_TIMER(vcp, 0);
+
+ return (0);
+}
+
+
+/*
+ * Free UNISIG 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 UNISIG 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
+unisig_free(vcp)
+ struct vccb *vcp;
+{
+ struct atm_pif *pip = vcp->vc_pif;
+ struct unisig *usp = (struct unisig *)pip->pif_siginst;
+
+ ATM_DEBUG1("unisig_free: vcp = 0x%x\n", vcp);
+
+ /*
+ * Make sure VCC has been closed
+ */
+ if ((vcp->vc_ustate != VCCU_CLOSED &&
+ vcp->vc_ustate != VCCU_ABORT) ||
+ vcp->vc_sstate != UNI_FREE) {
+ ATM_DEBUG2("unisig_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, usp->us_vccq);
+
+ /*
+ * Free VCCB storage
+ */
+ vcp->vc_ustate = VCCU_NULL;
+ vcp->vc_sstate = UNI_NULL;
+ atm_free((caddr_t)vcp);
+
+ /*
+ * If we're detaching and this was the last VCC queued,
+ * get rid of the protocol instance
+ */
+ if ((usp->us_state == UNISIG_DETACH) &&
+ (Q_HEAD(usp->us_vccq, struct vccb) == NULL)) {
+ struct sigmgr *smp = pip->pif_sigmgr;
+ int s = splimp();
+
+ pip->pif_sigmgr = NULL;
+ pip->pif_siginst = NULL;
+ (void) splx(s);
+
+ UNLINK((struct siginst *)usp, struct siginst,
+ smp->sm_prinst, si_next);
+ KM_FREE(usp, sizeof(struct unisig), M_DEVBUF);
+ }
+
+ return (0);
+}
+
+
+/*
+ * UNISIG 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
+unisig_ioctl(code, data, arg1)
+ int code;
+ caddr_t data;
+ caddr_t arg1;
+{
+ struct atmdelreq *adp;
+ struct atminfreq *aip;
+ struct atmsetreq *asp;
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct air_vcc_rsp rsp;
+ struct atm_pif *pip;
+ Atm_connection *cop;
+ u_int vpi, vci;
+ int err = 0, buf_len, i;
+ caddr_t buf_addr;
+
+ ATM_DEBUG1("unisig_ioctl: code=%d\n", code);
+
+ switch (code) {
+
+ case AIOCS_DEL_PVC:
+ case AIOCS_DEL_SVC:
+ /*
+ * Delete a VCC
+ */
+ adp = (struct atmdelreq *)data;
+ usp = (struct unisig *)arg1;
+
+ /*
+ * Don't let a user close the UNISIG signalling VC
+ */
+ vpi = adp->adr_pvc_vpi;
+ vci = adp->adr_pvc_vci;
+ if ((vpi == UNISIG_SIG_VPI && vci == UNISIG_SIG_VCI))
+ return(EINVAL);
+
+ /*
+ * Find requested VCC
+ */
+ for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp;
+ uvp = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem)) {
+ if ((uvp->uv_vpi == vpi) && (uvp->uv_vci == vci))
+ break;
+ }
+ if (uvp == NULL)
+ return (ENOENT);
+
+ /*
+ * Check VCC type
+ */
+ switch (code) {
+ case AIOCS_DEL_PVC:
+ if (!(uvp->uv_type & VCC_PVC)) {
+ return(EINVAL);
+ }
+ break;
+ case AIOCS_DEL_SVC:
+ if (!(uvp->uv_type & VCC_SVC)) {
+ return(EINVAL);
+ }
+ break;
+ }
+
+ /*
+ * Schedule VCC termination
+ */
+ unisig_set_cause_attr(&uvp->uv_connvc->cvc_attr,
+ T_ATM_CAUSE_UNSPECIFIED_NORMAL);
+ err = unisig_abort((struct vccb *)uvp);
+ break;
+
+ case AIOCS_INF_VCC:
+ /*
+ * Return VCC information
+ */
+ aip = (struct atminfreq *)data;
+ usp = (struct unisig *)arg1;
+
+ buf_addr = aip->air_buf_addr;
+ buf_len = aip->air_buf_len;
+
+ /*
+ * Loop through the VCC queue
+ */
+ for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp;
+ uvp = Q_NEXT(uvp, struct unisig_vccb, uv_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",
+ usp->us_pif->pif_name,
+ usp->us_pif->pif_unit);
+ rsp.avp_vpi = uvp->uv_vpi;
+ rsp.avp_vci = uvp->uv_vci;
+ rsp.avp_type = uvp->uv_type;
+ rsp.avp_aal = uvp->uv_connvc->cvc_attr.aal.type;
+ rsp.avp_sig_proto = uvp->uv_proto;
+ cop = uvp->uv_connvc->cvc_conn;
+ if (cop)
+ rsp.avp_encaps = cop->co_mpx;
+ else
+ rsp.avp_encaps = 0;
+ rsp.avp_state = uvp->uv_sstate;
+ if (uvp->uv_connvc->cvc_flags & CVCF_CALLER) {
+ rsp.avp_daddr = uvp->uv_connvc->cvc_attr.called.addr;
+ } else {
+ rsp.avp_daddr = uvp->uv_connvc->cvc_attr.calling.addr;
+ }
+ rsp.avp_dsubaddr.address_format = T_ATM_ABSENT;
+ rsp.avp_dsubaddr.address_length = 0;
+ rsp.avp_ipdus = uvp->uv_ipdus;
+ rsp.avp_opdus = uvp->uv_opdus;
+ rsp.avp_ibytes = uvp->uv_ibytes;
+ rsp.avp_obytes = uvp->uv_obytes;
+ rsp.avp_ierrors = uvp->uv_ierrors;
+ rsp.avp_oerrors = uvp->uv_oerrors;
+ rsp.avp_tstamp = uvp->uv_tstamp;
+ 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);
+ }
+
+ /*
+ * 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_INF_ARP:
+ case AIOCS_INF_ASV:
+ case AIOCS_SET_ASV:
+ /*
+ * Get ARP table information or get/set ARP server address
+ */
+ err = uniarp_ioctl(code, data, arg1);
+ break;
+
+ case AIOCS_SET_PRF:
+ /*
+ * Set NSAP prefix
+ */
+ asp = (struct atmsetreq *)data;
+ usp = (struct unisig *)arg1;
+ pip = usp->us_pif;
+ if (usp->us_addr.address_format != T_ATM_ABSENT) {
+ if (KM_CMP(asp->asr_prf_pref, usp->us_addr.address,
+ sizeof(asp->asr_prf_pref)) != 0)
+ err = EALREADY;
+ break;
+ }
+ usp->us_addr.address_format = T_ATM_ENDSYS_ADDR;
+ usp->us_addr.address_length = sizeof(Atm_addr_nsap);
+ KM_COPY(&pip->pif_macaddr,
+ ((Atm_addr_nsap *)usp->us_addr.address)->aan_esi,
+ sizeof(pip->pif_macaddr));
+ KM_COPY((caddr_t) asp->asr_prf_pref,
+ &((Atm_addr_nsap *)usp->us_addr.address)->aan_afi,
+ sizeof(asp->asr_prf_pref));
+ log(LOG_INFO, "uni: set address %s on interface %s\n",
+ unisig_addr_print(&usp->us_addr),
+ asp->asr_prf_intf);
+
+ /*
+ * Pass event to signalling manager state machine
+ */
+ err = unisig_sigmgr_state(usp, UNISIG_SIGMGR_ADDR_SET,
+ (KBuffer *) NULL);
+
+ /*
+ * Clean up if there was an error
+ */
+ if (err) {
+ usp->us_addr.address_format = T_ATM_ABSENT;
+ usp->us_addr.address_length = 0;
+ break;
+ }
+
+ /*
+ * Inform ARP code of new address
+ */
+ uniarp_ifaddr((struct siginst *)usp);
+ break;
+
+ default:
+ err = EOPNOTSUPP;
+ }
+
+ return (err);
+}
diff --git a/sys/netatm/uni/unisig_mbuf.c b/sys/netatm/uni/unisig_mbuf.c
new file mode 100644
index 0000000..84c78fe
--- /dev/null
+++ b/sys/netatm/uni/unisig_mbuf.c
@@ -0,0 +1,485 @@
+/*
+ *
+ * ===================================
+ * 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: unisig_mbuf.c,v 1.6 1998/08/26 23:29:22 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI 3.0/3.1 Signalling Manager
+ * ----------------------------------------
+ *
+ * Message buffer handling routines
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: unisig_mbuf.c,v 1.6 1998/08/26 23:29:22 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/unisig_var.h>
+#include <netatm/uni/unisig_mbuf.h>
+#include <netatm/uni/unisig_msg.h>
+
+
+/*
+ * Initialize a unisig formatting structure
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * usp pointer to a unisig protocol instance
+ * buf pointer to a buffer chain (decode only)
+ * op operation code (encode or decode)
+ * headroom headroom to leave in first buffer
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+usf_init(usf, usp, buf, op, headroom)
+ struct usfmt *usf;
+ struct unisig *usp;
+ KBuffer *buf;
+ int op;
+ int headroom;
+{
+ KBuffer *m;
+
+ ATM_DEBUG3("usf_init: usf=0x%x, buf=0x%x, op=%d\n",
+ (int) usf, (int) buf, op);
+
+ /*
+ * Check parameters
+ */
+ if (!usf)
+ return(EINVAL);
+
+ switch(op) {
+
+ case USF_ENCODE:
+ /*
+ * Get a buffer
+ */
+ KB_ALLOCPKT(m, USF_MIN_ALLOC, KB_F_NOWAIT, KB_T_DATA);
+ if (m == NULL)
+ return(ENOMEM);
+ KB_LEN(m) = 0;
+ if (headroom < KB_BFRLEN(m)) {
+ KB_HEADSET(m, headroom);
+ }
+ break;
+
+ case USF_DECODE:
+ /*
+ * Verify buffer address
+ */
+ if (!buf)
+ return(EINVAL);
+ m = buf;
+ break;
+
+ default:
+ return(EINVAL);
+ }
+
+ /*
+ * Save parameters in formatting structure
+ */
+ usf->usf_m_addr = m;
+ usf->usf_m_base = m;
+ usf->usf_loc = 0;
+ usf->usf_op = op;
+ usf->usf_sig = usp;
+
+ return(0);
+}
+
+
+/*
+ * Get or put the next byte of a signalling message
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * c pointer to the byte to send from or receive into
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+usf_byte(usf, c)
+ struct usfmt *usf;
+ u_char *c;
+{
+ u_char *mp;
+ KBuffer *m = usf->usf_m_addr, *m1;
+ int space;
+
+ switch (usf->usf_op) {
+
+ case USF_DECODE:
+ /*
+ * Make sure we're not past the end of the buffer
+ * (allowing for zero-length buffers)
+ */
+ while (usf->usf_loc >= KB_LEN(m)) {
+ if (KB_NEXT(usf->usf_m_addr)) {
+ usf->usf_m_addr = m = KB_NEXT(usf->usf_m_addr);
+ usf->usf_loc = 0;
+ } else {
+ return(EMSGSIZE);
+ }
+ }
+
+ /*
+ * Get the data from the buffer
+ */
+ KB_DATASTART(m, mp, u_char *);
+ *c = mp[usf->usf_loc];
+ usf->usf_loc++;
+ break;
+
+ case USF_ENCODE:
+ /*
+ * If the current buffer is full, get another
+ */
+ KB_TAILROOM(m, space);
+ if (space == 0) {
+ KB_ALLOC(m1, USF_MIN_ALLOC, KB_F_NOWAIT, KB_T_DATA);
+ if (m1 == NULL)
+ return(ENOMEM);
+ KB_LEN(m1) = 0;
+ KB_LINK(m1, m);
+ usf->usf_m_addr = m = m1;
+ usf->usf_loc = 0;
+ }
+
+ /*
+ * Put the data into the buffer
+ */
+ KB_DATASTART(m, mp, u_char *);
+ mp[usf->usf_loc] = *c;
+ KB_TAILADJ(m, 1);
+ usf->usf_loc++;
+ break;
+
+ default:
+ /*
+ * Invalid operation code
+ */
+ return(EINVAL);
+ }
+
+ return(0);
+
+}
+
+/*
+ * Get or put a short integer
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * s pointer to a short to send from or receive into
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+usf_short(usf, s)
+ struct usfmt *usf;
+ u_short *s;
+
+{
+ int rc;
+ union {
+ u_short value;
+ u_char b[sizeof(u_short)];
+ } tval;
+
+ tval.value = 0;
+ if (usf->usf_op == USF_ENCODE)
+ tval.value = htons(*s);
+
+ if (rc = usf_byte(usf, &tval.b[0]))
+ return(rc);
+ if (rc = usf_byte(usf, &tval.b[1]))
+ return(rc);
+
+ if (usf->usf_op == USF_DECODE)
+ *s = ntohs(tval.value);
+
+ return(0);
+}
+
+
+/*
+ * Get or put a 3-byte integer
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * i pointer to an integer to send from or receive into
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+usf_int3(usf, i)
+ struct usfmt *usf;
+ u_int *i;
+
+{
+ int j, rc;
+ union {
+ u_int value;
+ u_char b[sizeof(u_int)];
+ } tval;
+
+ tval.value = 0;
+
+ if (usf->usf_op == USF_ENCODE)
+ tval.value = htonl(*i);
+
+ for (j=0; j<3; j++) {
+ rc = usf_byte(usf, &tval.b[j+sizeof(u_int)-3]);
+ if (rc)
+ return(rc);
+ }
+
+ if (usf->usf_op == USF_DECODE)
+ *i = ntohl(tval.value);
+
+ return(rc);
+}
+
+
+/*
+ * Get or put an integer
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * i pointer to an integer to send from or receive into
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+usf_int(usf, i)
+ struct usfmt *usf;
+ u_int *i;
+
+{
+ int j, rc;
+ union {
+ u_int value;
+ u_char b[sizeof(u_int)];
+ } tval;
+
+ if (usf->usf_op == USF_ENCODE)
+ tval.value = htonl(*i);
+
+ for (j=0; j<4; j++) {
+ rc = usf_byte(usf, &tval.b[j+sizeof(u_int)-4]);
+ if (rc)
+ return(rc);
+ }
+
+ if (usf->usf_op == USF_DECODE)
+ *i = ntohl(tval.value);
+
+ return(rc);
+}
+
+
+/*
+ * Get or put an extented field
+ *
+ * An extented field consists of a string of bytes. All but the last
+ * byte of the field has the high-order bit set to zero. When decoding,
+ * this routine will read bytes until either the input is exhausted or
+ * a byte with a high-order one is found. Whe encoding, it will take an
+ * unsigned integer and write until the highest-order one bit has been
+ * written.
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * i pointer to an integer to send from or receive into
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+usf_ext(usf, i)
+ struct usfmt *usf;
+ u_int *i;
+
+{
+ int j, rc;
+ u_char c, buff[sizeof(u_int)+1];
+ u_int val;
+ union {
+ u_int value;
+ u_char b[sizeof(u_int)];
+ } tval;
+
+ switch(usf->usf_op) {
+
+ case USF_ENCODE:
+ val = *i;
+ j = 0;
+ while (val) {
+ tval.value = htonl(val);
+ buff[j] = tval.b[sizeof(u_int)-1] & UNI_IE_EXT_MASK;
+ val >>= 7;
+ j++;
+ }
+ j--;
+ buff[0] |= UNI_IE_EXT_BIT;
+ for (; j>=0; j--) {
+ rc = usf_byte(usf, &buff[j]);
+ if (rc)
+ return(rc);
+ }
+ break;
+
+ case USF_DECODE:
+ c = 0;
+ val = 0;
+ while (!(c & UNI_IE_EXT_BIT)) {
+ rc = usf_byte(usf, &c);
+ if (rc)
+ return(rc);
+ val = (val << 7) + (c & UNI_IE_EXT_MASK);
+ }
+ *i = val;
+ break;
+
+ default:
+ return(EINVAL);
+ }
+
+ return(0);
+}
+
+
+/*
+ * Count the bytes remaining to be decoded
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ *
+ * Returns:
+ * int the number of bytes in the buffer chain remaining to
+ * be decoded
+ *
+ */
+int
+usf_count(usf)
+ struct usfmt *usf;
+{
+ int count;
+ KBuffer *m = usf->usf_m_addr;
+
+ /*
+ * Return zero if we're not decoding
+ */
+ if (usf->usf_op != USF_DECODE)
+ return (0);
+
+ /*
+ * Calculate the length of data remaining in the current buffer
+ */
+ count = KB_LEN(m) - usf->usf_loc;
+
+ /*
+ * Loop through any remaining buffers, adding in their lengths
+ */
+ while (KB_NEXT(m)) {
+ m = KB_NEXT(m);
+ count += KB_LEN(m);
+ }
+
+ return(count);
+
+}
+
+
+/*
+ * Get or put the next byte of a signalling message and return
+ * the byte's buffer address
+ *
+ * Arguments:
+ * usf pointer to a unisig formatting structure
+ * c pointer to the byte to send from or receive into
+ * bp address to store the byte's buffer address
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+usf_byte_mark(usf, c, bp)
+ struct usfmt *usf;
+ u_char *c;
+ u_char **bp;
+{
+ u_char *mp;
+ int rc;
+
+ /*
+ * First, get/put the data byte
+ */
+ rc = usf_byte(usf, c);
+ if (rc) {
+
+ /*
+ * Error encountered
+ */
+ *bp = NULL;
+ return (rc);
+ }
+
+ /*
+ * Now return the buffer address of that byte
+ */
+ KB_DATASTART(usf->usf_m_addr, mp, u_char *);
+ *bp = &mp[usf->usf_loc - 1];
+
+ return (0);
+}
+
diff --git a/sys/netatm/uni/unisig_mbuf.h b/sys/netatm/uni/unisig_mbuf.h
new file mode 100644
index 0000000..f394047
--- /dev/null
+++ b/sys/netatm/uni/unisig_mbuf.h
@@ -0,0 +1,58 @@
+/*
+ *
+ * ===================================
+ * 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: unisig_mbuf.h,v 1.5 1998/08/26 23:29:22 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI 3.0/3.1 Signalling Manager
+ * ----------------------------------------
+ *
+ * Message buffer formats
+ *
+ */
+
+#ifndef _UNI_SIG_MBUF_H
+#define _UNI_SIG_MBUF_H
+
+
+/*
+ * Structure for message encoding/decoding information.
+ */
+struct usfmt {
+ KBuffer *usf_m_addr; /* Current buffer */
+ KBuffer *usf_m_base; /* First buffer in chain */
+ int usf_loc; /* Offset in current buffer */
+ int usf_op; /* Operation (see below) */
+ struct unisig *usf_sig; /* UNI signalling instance */
+};
+
+#define USF_ENCODE 1
+#define USF_DECODE 2
+
+#define USF_MIN_ALLOC MHLEN /* Minimum encoding buffer size */
+
+#endif /* _UNI_SIG_MBUF_H */
diff --git a/sys/netatm/uni/unisig_msg.c b/sys/netatm/uni/unisig_msg.c
new file mode 100644
index 0000000..22bf469
--- /dev/null
+++ b/sys/netatm/uni/unisig_msg.c
@@ -0,0 +1,1002 @@
+/*
+ *
+ * ===================================
+ * 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: unisig_msg.c,v 1.10 1998/08/26 23:29:22 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI 3.0/3.1 Signalling Manager
+ * ----------------------------------------
+ *
+ * Message handling module
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: unisig_msg.c,v 1.10 1998/08/26 23:29:22 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/unisig.h>
+#include <netatm/uni/unisig_var.h>
+#include <netatm/uni/unisig_msg.h>
+#include <netatm/uni/unisig_mbuf.h>
+#include <netatm/uni/unisig_print.h>
+
+
+/*
+ * Local functions
+ */
+static void unisig_rcv_restart __P((struct unisig *, struct unisig_msg *));
+static void unisig_rcv_setup __P((struct unisig *, struct unisig_msg *));
+
+
+/*
+ * Local variables
+ */
+#ifdef DIAGNOSTIC
+static int unisig_print_msg = 0;
+#endif
+
+
+/*
+ * Set a Cause IE based on information in an ATM attribute block
+ *
+ * Arguments:
+ * iep pointer to a cause IE
+ * msg pointer to message
+ * cause cause code for the error
+ *
+ * Returns:
+ * 0 message sent OK
+ * errno error encountered
+ *
+ */
+void
+unisig_cause_from_attr(iep, aap)
+ struct ie_generic *iep;
+ Atm_attributes *aap;
+{
+ /*
+ * Copy cause info from attribute block to IE
+ */
+ iep->ie_ident = UNI_IE_CAUS;
+ iep->ie_coding = aap->cause.v.coding_standard;
+ iep->ie_caus_loc = aap->cause.v.location;
+ iep->ie_caus_cause = aap->cause.v.cause_value;
+}
+
+
+/*
+ * Set a Cause IE based on information in a UNI signalling message
+ *
+ * Arguments:
+ * iep pointer to a cause IE
+ * msg pointer to message
+ * cause cause code for the error
+ *
+ * Returns:
+ * 0 message sent OK
+ * errno error encountered
+ *
+ */
+void
+unisig_cause_from_msg(iep, msg, cause)
+ struct ie_generic *iep;
+ struct unisig_msg *msg;
+ int cause;
+{
+ struct ie_generic *ie1;
+ int i;
+
+ /*
+ * Fill out the cause IE fixed fields
+ */
+ iep->ie_ident = UNI_IE_CAUS;
+ iep->ie_caus_loc = UNI_IE_CAUS_LOC_USER;
+ iep->ie_caus_cause = cause;
+
+ /*
+ * Set diagnostics if indicated
+ */
+ switch(cause) {
+ case UNI_IE_CAUS_IECONTENT:
+ iep->ie_caus_diag_len = 0;
+ for (i = 0, ie1 = msg->msg_ie_err;
+ ie1 && i < UNI_IE_CAUS_MAX_ID;
+ ie1 = ie1->ie_next) {
+ if (ie1->ie_err_cause == UNI_IE_CAUS_IECONTENT) {
+ iep->ie_caus_diagnostic[i] =
+ ie1->ie_ident;
+ iep->ie_caus_diag_len++;
+ i++;
+ }
+ }
+ break;
+ case UNI_IE_CAUS_REJECT:
+ iep->ie_caus_diag_len = 2;
+ iep->ie_caus_diagnostic[0] = UNI_IE_EXT_BIT +
+ (UNI_IE_CAUS_RR_USER << UNI_IE_CAUS_RR_SHIFT) +
+ UNI_IE_CAUS_RC_TRANS;
+ iep->ie_caus_diagnostic[1] = 0;
+ break;
+ case UNI_IE_CAUS_MISSING:
+ iep->ie_caus_diag_len = 0;
+ for (i = 0, ie1 = msg->msg_ie_err;
+ ie1 && i < UNI_IE_CAUS_MAX_ID;
+ ie1 = ie1->ie_next) {
+ if (ie1->ie_err_cause == UNI_IE_CAUS_MISSING) {
+ iep->ie_caus_diagnostic[i] =
+ ie1->ie_ident;
+ iep->ie_caus_diag_len++;
+ i++;
+ }
+ }
+ }
+}
+
+
+/*
+ * Send a UNISIG signalling message
+ *
+ * Called to send a Q.2931 message. This routine encodes the message
+ * and hands it to SSCF for transmission.
+ *
+ * Arguments:
+ * usp pointer to UNISIG protocol instance block
+ * msg pointer to message
+ *
+ * Returns:
+ * 0 message sent OK
+ * errno error encountered
+ *
+ */
+int
+unisig_send_msg(usp, msg)
+ struct unisig *usp;
+ struct unisig_msg *msg;
+{
+ int err = 0;
+ struct usfmt usf;
+
+ ATM_DEBUG2("unisig_send_msg: msg=0x%x, type=%d\n", msg,
+ msg->msg_type);
+
+ /*
+ * Make sure the network is up
+ */
+ if (usp->us_state != UNISIG_ACTIVE)
+ return(ENETDOWN);
+
+#ifdef DIAGNOSTIC
+ /*
+ * Print the message we're sending.
+ */
+ if (unisig_print_msg)
+ usp_print_msg(msg, UNISIG_MSG_OUT);
+#endif
+
+ /*
+ * Convert message to network order
+ */
+ err = usf_init(&usf, usp, (KBuffer *) 0, USF_ENCODE,
+ usp->us_headout);
+ if (err)
+ return(err);
+
+ err = usf_enc_msg(&usf, msg);
+ if (err) {
+ ATM_DEBUG1("unisig_send_msg: encode failed with %d\n",
+ err);
+ KB_FREEALL(usf.usf_m_base);
+ return(EIO);
+ }
+
+#ifdef DIAGNOSTIC
+ /*
+ * Print the converted message
+ */
+ if (unisig_print_msg > 1)
+ unisig_print_mbuf(usf.usf_m_base);
+#endif
+
+ /*
+ * Send the message
+ */
+ err = atm_cm_saal_data(usp->us_conn, usf.usf_m_base);
+ if (err)
+ KB_FREEALL(usf.usf_m_base);
+
+ return(err);
+}
+
+
+/*
+ * Send a SETUP request
+ *
+ * Build and send a Q.2931 SETUP message.
+ *
+ * Arguments:
+ * usp pointer to UNISIG protocol instance block
+ * uvp pointer to VCCB for which the request is being sent
+ *
+ * Returns:
+ * none
+ *
+ */
+int
+unisig_send_setup(usp, uvp)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+{
+ int err = 0;
+ struct unisig_msg *setup;
+ Atm_attributes *ap = &uvp->uv_connvc->cvc_attr;
+
+ ATM_DEBUG1("unisig_send_setup: uvp=0x%x\n", (int) uvp);
+
+ /*
+ * Make sure required connection attriutes are set
+ */
+ if (ap->aal.tag != T_ATM_PRESENT ||
+ ap->traffic.tag != T_ATM_PRESENT ||
+ ap->bearer.tag != T_ATM_PRESENT ||
+ ap->called.tag != T_ATM_PRESENT ||
+ ap->qos.tag != T_ATM_PRESENT) {
+ err = EINVAL;
+ setup = NULL;
+ goto done;
+ }
+
+ /*
+ * Get memory for a SETUP message
+ */
+ setup = (struct unisig_msg *)atm_allocate(&unisig_msgpool);
+ if (setup == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+
+ /*
+ * Fill in the SETUP message
+ */
+ if (!uvp->uv_call_ref)
+ uvp->uv_call_ref = unisig_alloc_call_ref(usp);
+ setup->msg_call_ref = uvp->uv_call_ref;
+ setup->msg_type = UNI_MSG_SETU;
+
+ /*
+ * Set IEs from connection attributes
+ */
+ err = unisig_set_attrs(usp, setup, ap);
+ if (err)
+ goto done;
+
+ /*
+ * Attach a Calling Party Number IE if the user didn't
+ * specify one in the attribute block
+ */
+ if (ap->calling.tag != T_ATM_PRESENT) {
+ setup->msg_ie_cgad = (struct ie_generic *)
+ atm_allocate(&unisig_iepool);
+ if (setup->msg_ie_cgad == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+ setup->msg_ie_cgad->ie_ident = UNI_IE_CGAD;
+ ATM_ADDR_COPY(&usp->us_addr,
+ &setup->msg_ie_cgad->ie_cgad_addr);
+ ATM_ADDR_SEL_COPY(&usp->us_addr,
+ uvp->uv_nif ? uvp->uv_nif->nif_sel : 0,
+ &setup->msg_ie_cgad->ie_cgad_addr);
+ }
+
+ /*
+ * Send the SETUP message
+ */
+ err = unisig_send_msg(usp, setup);
+
+done:
+ if (setup)
+ unisig_free_msg(setup);
+
+ return(err);
+}
+
+
+/*
+ * Send a RELEASE message
+ *
+ * Arguments:
+ * usp pointer to UNISIG protocol instance block
+ * uvp pointer to VCCB for which the RELEASE is being sent
+ * msg pointer to UNI signalling message that the RELEASE
+ * responds to (may be NULL)
+ * cause the reason for the RELEASE; a value of
+ * T_ATM_ABSENT indicates that the cause code is
+ * in the VCC's ATM attributes block
+ *
+ * Returns:
+ * none
+ *
+ */
+int
+unisig_send_release(usp, uvp, msg, cause)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+ int cause;
+{
+ int err = 0;
+ struct unisig_msg *rls_msg;
+ struct ie_generic *cause_ie;
+
+ ATM_DEBUG2("unisig_send_release: usp=0x%x, uvp=0x%x\n",
+ (int) usp, (int) uvp);
+
+ /*
+ * Get memory for a RELEASE message
+ */
+ rls_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
+ if (rls_msg == NULL) {
+ return(ENOMEM);
+ }
+ cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
+ if (cause_ie == NULL) {
+ atm_free(rls_msg);
+ return(ENOMEM);
+ }
+
+ /*
+ * Fill in the RELEASE message
+ */
+ rls_msg->msg_call_ref = uvp->uv_call_ref;
+ rls_msg->msg_type = UNI_MSG_RLSE;
+ rls_msg->msg_type_flag = 0;
+ rls_msg->msg_type_action = 0;
+ rls_msg->msg_ie_caus = cause_ie;
+
+ /*
+ * Fill out the cause IE
+ */
+ cause_ie->ie_ident = UNI_IE_CAUS;
+ if (cause == T_ATM_ABSENT) {
+ unisig_cause_from_attr(cause_ie,
+ &uvp->uv_connvc->cvc_attr);
+ } else {
+ cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER;
+ unisig_cause_from_msg(cause_ie, msg, cause);
+ }
+
+ /*
+ * Send the RELEASE
+ */
+ err = unisig_send_msg(usp, rls_msg);
+ unisig_free_msg(rls_msg);
+
+ return(err);
+}
+
+
+/*
+ * Send a RELEASE COMPLETE message
+ *
+ * Arguments:
+ * usp pointer to UNISIG protocol instance block
+ * uvp pointer to VCCB for which the RELEASE is being sent.
+ * NULL indicates that a VCCB wasn't found for a call
+ * reference value.
+ * msg pointer to the message which triggered the send
+ * cause the cause code for the message; a value of
+ * T_ATM_ABSENT indicates that the cause code is
+ * in the VCC's ATM attributes block
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+unisig_send_release_complete(usp, uvp, msg, cause)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+ int cause;
+{
+ int err = 0;
+ struct unisig_msg *rls_cmp;
+ struct ie_generic *cause_ie;
+
+ ATM_DEBUG4("unisig_send_release_complete usp=0x%x, uvp=0x%x, msg=0x%x, cause=%d\n",
+ (int) usp, (int) uvp, (int) msg, cause);
+
+ /*
+ * Get memory for a RELEASE COMPLETE message
+ */
+ rls_cmp = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
+ if (rls_cmp == NULL) {
+ return(ENOMEM);
+ }
+ cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
+ if (cause_ie == NULL) {
+ atm_free(rls_cmp);
+ return(ENOMEM);
+ }
+
+ /*
+ * Fill in the RELEASE COMPLETE message
+ */
+ if (uvp) {
+ rls_cmp->msg_call_ref = uvp->uv_call_ref;
+ } else if (msg) {
+ rls_cmp->msg_call_ref = EXTRACT_CREF(msg->msg_call_ref);
+ } else {
+ rls_cmp->msg_call_ref = UNI_MSG_CALL_REF_GLOBAL;
+ }
+ rls_cmp->msg_type = UNI_MSG_RLSC;
+ rls_cmp->msg_type_flag = 0;
+ rls_cmp->msg_type_action = 0;
+ rls_cmp->msg_ie_caus = cause_ie;
+
+ /*
+ * Fill out the cause IE
+ */
+ cause_ie->ie_ident = UNI_IE_CAUS;
+ if (cause == T_ATM_ABSENT) {
+ unisig_cause_from_attr(cause_ie,
+ &uvp->uv_connvc->cvc_attr);
+ } else {
+ cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER;
+ unisig_cause_from_msg(cause_ie, msg, cause);
+ }
+
+ /*
+ * Send the RELEASE COMPLETE
+ */
+ err = unisig_send_msg(usp, rls_cmp);
+ unisig_free_msg(rls_cmp);
+
+ return(err);
+}
+
+
+/*
+ * Send a STATUS message
+ *
+ * Arguments:
+ * usp pointer to UNISIG protocol instance block
+ * uvp pointer to VCCB for which the STATUS is being sent.
+ * NULL indicates that a VCCB wasn't found for a call
+ * reference value.
+ * msg pointer to the message which triggered the send
+ * cause the cause code to include in the message
+ *
+ * Returns:
+ * none
+ *
+ */
+int
+unisig_send_status(usp, uvp, msg, cause)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+ int cause;
+{
+ int err = 0, i;
+ struct unisig_msg *stat_msg;
+ struct ie_generic *cause_ie, *clst_ie, *iep;
+
+ ATM_DEBUG4("unisig_send_status: usp=0x%x, uvp=0x%x, msg=0x%x, cause=%d\n",
+ (int) usp, (int) uvp, (int) msg, cause);
+
+ /*
+ * Get memory for a STATUS message
+ */
+ stat_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
+ if (stat_msg == NULL) {
+ return(ENOMEM);
+ }
+ cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
+ if (cause_ie == NULL) {
+ atm_free(stat_msg);
+ return(ENOMEM);
+ }
+ clst_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
+ if (clst_ie == NULL) {
+ atm_free(stat_msg);
+ atm_free(cause_ie);
+ return(ENOMEM);
+ }
+
+ /*
+ * Fill in the STATUS message
+ */
+ if (uvp) {
+ stat_msg->msg_call_ref = uvp->uv_call_ref;
+ } else if (msg) {
+ stat_msg->msg_call_ref =
+ EXTRACT_CREF(msg->msg_call_ref);
+ } else {
+ stat_msg->msg_call_ref = UNI_MSG_CALL_REF_GLOBAL;
+ }
+ stat_msg->msg_type = UNI_MSG_STAT;
+ stat_msg->msg_type_flag = 0;
+ stat_msg->msg_type_action = 0;
+ stat_msg->msg_ie_clst = clst_ie;
+ stat_msg->msg_ie_caus = cause_ie;
+
+ /*
+ * Fill out the call state IE
+ */
+ clst_ie->ie_ident = UNI_IE_CLST;
+ clst_ie->ie_coding = 0;
+ clst_ie->ie_flag = 0;
+ clst_ie->ie_action = 0;
+ if (uvp) {
+ clst_ie->ie_clst_state = uvp->uv_sstate;
+ } else {
+ clst_ie->ie_clst_state = UNI_NULL;
+ }
+
+ /*
+ * Fill out the cause IE
+ */
+ cause_ie->ie_ident = UNI_IE_CAUS;
+ cause_ie->ie_coding = 0;
+ cause_ie->ie_flag = 0;
+ cause_ie->ie_action = 0;
+ cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER;
+ cause_ie->ie_caus_cause = cause;
+ switch (cause) {
+ case UNI_IE_CAUS_MTEXIST:
+ case UNI_IE_CAUS_STATE:
+ if (msg) {
+ cause_ie->ie_caus_diagnostic[0] = msg->msg_type;
+ }
+ break;
+ case UNI_IE_CAUS_MISSING:
+ case UNI_IE_CAUS_IECONTENT:
+ case UNI_IE_CAUS_IEEXIST:
+ for (i=0, iep=msg->msg_ie_err;
+ iep && i<UNI_MSG_IE_CNT;
+ i++, iep = iep->ie_next) {
+ if (iep->ie_err_cause == cause) {
+ cause_ie->ie_caus_diagnostic[i] =
+ iep->ie_ident;
+ }
+ }
+ }
+
+ /*
+ * Send the STATUS message
+ */
+ err = unisig_send_msg(usp, stat_msg);
+ unisig_free_msg(stat_msg);
+
+ return(err);
+}
+
+
+/*
+ * Process a RESTART message
+ *
+ * Arguments:
+ * usp pointer to UNISIG protocol instance block
+ * msg pointer to the RESTART message
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+unisig_rcv_restart(usp, msg)
+ struct unisig *usp;
+ struct unisig_msg *msg;
+{
+ struct unisig_vccb *uvp, *uvnext;
+ struct unisig_msg *rsta_msg;
+ int s;
+
+ ATM_DEBUG2("unisig_rcv_restart: usp=0x%x, msg=0x%x\n",
+ usp, msg);
+
+ /*
+ * Check what class of VCCs we're supposed to restart
+ */
+ if (msg->msg_ie_rsti->ie_rsti_class == UNI_IE_RSTI_IND_VC) {
+ /*
+ * Just restart the indicated VCC
+ */
+ if (msg->msg_ie_cnid) {
+ uvp = unisig_find_vpvc(usp,
+ msg->msg_ie_cnid->ie_cnid_vpci,
+ msg->msg_ie_cnid->ie_cnid_vci,
+ 0);
+ if (uvp && uvp->uv_type & VCC_SVC) {
+ (void) unisig_clear_vcc(usp, uvp,
+ T_ATM_CAUSE_NORMAL_CALL_CLEARING);
+ }
+ }
+ } else {
+ /*
+ * Restart all VCCs
+ */
+ s = splnet();
+ for (uvp=Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp;
+ uvp=uvnext) {
+ uvnext = Q_NEXT(uvp, struct unisig_vccb,
+ uv_sigelem);
+ if (uvp->uv_type & VCC_SVC) {
+ (void) unisig_clear_vcc(usp, uvp,
+ T_ATM_CAUSE_NORMAL_CALL_CLEARING);
+ }
+ }
+ (void) splx(s);
+ }
+
+ /*
+ * Get memory for a RESTART ACKNOWLEDGE message
+ */
+ rsta_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
+ if (rsta_msg == NULL) {
+ return;
+ }
+
+ /*
+ * Fill out the message
+ */
+ rsta_msg->msg_call_ref = EXTRACT_CREF(msg->msg_call_ref);
+ rsta_msg->msg_type = UNI_MSG_RSTA;
+ rsta_msg->msg_type_flag = 0;
+ rsta_msg->msg_type_action = 0;
+ rsta_msg->msg_ie_rsti = msg->msg_ie_rsti;
+ if (msg->msg_ie_cnid) {
+ rsta_msg->msg_ie_cnid = msg->msg_ie_cnid;
+ }
+
+ /*
+ * Send the message
+ */
+ (void) unisig_send_msg(usp, rsta_msg);
+ rsta_msg->msg_ie_rsti = NULL;
+ rsta_msg->msg_ie_cnid = NULL;
+ unisig_free_msg(rsta_msg);
+
+ return;
+}
+
+
+/*
+ * Process a SETUP message
+ *
+ * Arguments:
+ * usp pointer to UNISIG protocol instance block
+ * msg pointer to the SETUP message
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+unisig_rcv_setup(usp, msg)
+ struct unisig *usp;
+ struct unisig_msg *msg;
+{
+ struct unisig_vccb *uvp = NULL;
+ struct ie_generic *iep;
+
+ ATM_DEBUG2("unisig_rcv_setup: usp=0x%x, msg=0x%x\n", usp, msg);
+
+ /*
+ * If we already have a VCC with the call reference,
+ * ignore the SETUP message
+ */
+ uvp = unisig_find_conn(usp, EXTRACT_CREF(msg->msg_call_ref));
+ if (uvp)
+ return;
+
+ /*
+ * If the call reference flag is incorrectly set,
+ * ignore the SETUP message
+ */
+ if (msg->msg_call_ref & UNI_MSG_CALL_REF_RMT)
+ return;
+
+ /*
+ * If there are missing mandatory IEs, send a
+ * RELEASE COMPLETE message and ignore the SETUP
+ */
+ for (iep = msg->msg_ie_err; iep; iep = iep->ie_next) {
+ if (iep->ie_err_cause == UNI_IE_CAUS_MISSING) {
+ (void) unisig_send_release_complete(usp,
+ uvp, msg, UNI_IE_CAUS_MISSING);
+ return;
+ }
+ }
+
+ /*
+ * If there are mandatory IEs with invalid content, send a
+ * RELEASE COMPLETE message and ignore the SETUP
+ */
+ for (iep = msg->msg_ie_err; iep; iep = iep->ie_next) {
+ if (iep->ie_err_cause == UNI_IE_CAUS_IECONTENT) {
+ (void) unisig_send_release_complete(usp,
+ uvp, msg,
+ UNI_IE_CAUS_IECONTENT);
+ return;
+ }
+ }
+
+ /*
+ * Get a new VCCB for the connection
+ */
+ uvp = (struct unisig_vccb *)atm_allocate(&unisig_vcpool);
+ if (uvp == NULL) {
+ return;
+ }
+
+ /*
+ * Put the VCCB on the UNISIG queue
+ */
+ ENQUEUE(uvp, struct unisig_vccb, uv_sigelem, usp->us_vccq);
+
+ /*
+ * Set the state and call reference value
+ */
+ uvp->uv_sstate = UNI_NULL;
+ uvp->uv_call_ref = EXTRACT_CREF(msg->msg_call_ref);
+
+ /*
+ * Pass the VCCB and message to the VC state machine
+ */
+ (void) unisig_vc_state(usp, uvp, UNI_VC_SETUP_MSG, msg);
+
+ /*
+ * If the VCCB state is NULL, the open failed and the
+ * VCCB should be released
+ */
+ if (uvp->uv_sstate == UNI_NULL) {
+ DEQUEUE(uvp, struct unisig_vccb, uv_sigelem,
+ usp->us_vccq);
+ atm_free(uvp);
+ }
+
+ return;
+}
+
+
+/*
+ * Process a UNISIG signalling message
+ *
+ * Called when a UNISIG message is received. The message is decoded
+ * and passed to the UNISIG state machine. Unrecognized and
+ * unexpected messages are logged.
+ *
+ * Arguments:
+ * usp pointer to UNISIG protocol instance block
+ * m pointer to a buffer chain containing the UNISIG message
+ *
+ * Returns:
+ * none
+ *
+ */
+int
+unisig_rcv_msg(usp, m)
+ struct unisig *usp;
+ KBuffer *m;
+{
+ int err;
+ u_int cref;
+ struct usfmt usf;
+ struct unisig_msg *msg = 0;
+ struct unisig_vccb *uvp = 0;
+ struct ie_generic *iep;
+
+ ATM_DEBUG2("unisig_rcv_msg: bfr=0x%x, len=%d\n", (int)m, KB_LEN(m));
+
+#ifdef NOTDEF
+ unisig_print_mbuf(m);
+#endif
+
+ /*
+ * Get storage for the message
+ */
+ msg = (struct unisig_msg *)atm_allocate(&unisig_msgpool);
+ if (msg == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+
+ /*
+ * Convert the message from network order to internal format
+ */
+ err = usf_init(&usf, usp, m, USF_DECODE, 0);
+ if (err) {
+ if (err == EINVAL)
+ panic("unisig_rcv_msg: invalid parameter\n");
+ ATM_DEBUG1("unisig_rcv_msg: decode init failed with %d\n",
+ err);
+ goto done;
+ }
+
+ err = usf_dec_msg(&usf, msg);
+ if (err) {
+ ATM_DEBUG1("unisig_rcv_msg: decode failed with %d\n",
+ err);
+ goto done;
+ }
+
+#ifdef DIAGNOSTIC
+ /*
+ * Debug--print some information about the message
+ */
+ if (unisig_print_msg)
+ usp_print_msg(msg, UNISIG_MSG_IN);
+#endif
+
+ /*
+ * Get the call reference value
+ */
+ cref = EXTRACT_CREF(msg->msg_call_ref);
+
+ /*
+ * Any message with the global call reference value except
+ * RESTART, RESTART ACK, or STATUS is in error
+ */
+ if (GLOBAL_CREF(cref) &&
+ msg->msg_type != UNI_MSG_RSTR &&
+ msg->msg_type != UNI_MSG_RSTA &&
+ msg->msg_type != UNI_MSG_STAT) {
+ /*
+ * Send STATUS message indicating the error
+ */
+ err = unisig_send_status(usp, (struct unisig_vccb *) 0,
+ msg, UNI_IE_CAUS_CREF);
+ goto done;
+ }
+
+ /*
+ * Check for missing mandatory IEs. Checks for SETUP,
+ * RELEASE, and RELEASE COMPLETE are handled elsewhere.
+ */
+ if (msg->msg_type != UNI_MSG_SETU &&
+ msg->msg_type != UNI_MSG_RLSE &&
+ msg->msg_type != UNI_MSG_RLSC) {
+ for (iep = msg->msg_ie_err; iep; iep = iep->ie_next) {
+ if (iep->ie_err_cause == UNI_IE_CAUS_MISSING) {
+ err = unisig_send_status(usp,
+ uvp, msg,
+ UNI_IE_CAUS_MISSING);
+ goto done;
+ }
+ }
+ }
+
+ /*
+ * Find the VCCB associated with the message
+ */
+ uvp = unisig_find_conn(usp, cref);
+
+ /*
+ * Process the message based on its type
+ */
+ switch(msg->msg_type) {
+ case UNI_MSG_CALP:
+ (void) unisig_vc_state(usp, uvp,
+ UNI_VC_CALLP_MSG, msg);
+ break;
+ case UNI_MSG_CONN:
+ (void) unisig_vc_state(usp, uvp,
+ UNI_VC_CONNECT_MSG, msg);
+ break;
+ case UNI_MSG_CACK:
+ (void) unisig_vc_state(usp, uvp,
+ UNI_VC_CNCTACK_MSG, msg);
+ break;
+ case UNI_MSG_SETU:
+ unisig_rcv_setup(usp, msg);
+ break;
+ case UNI_MSG_RLSE:
+ (void) unisig_vc_state(usp, uvp,
+ UNI_VC_RELEASE_MSG, msg);
+ break;
+ case UNI_MSG_RLSC:
+ /*
+ * Ignore a RELEASE COMPLETE with an unrecognized
+ * call reference value
+ */
+ if (uvp) {
+ (void) unisig_vc_state(usp, uvp,
+ UNI_VC_RLSCMP_MSG, msg);
+ }
+ break;
+ case UNI_MSG_RSTR:
+ unisig_rcv_restart(usp, msg);
+ break;
+ case UNI_MSG_RSTA:
+ break;
+ case UNI_MSG_STAT:
+ (void) unisig_vc_state(usp, uvp,
+ UNI_VC_STATUS_MSG, msg);
+ break;
+ case UNI_MSG_SENQ:
+ (void) unisig_vc_state(usp, uvp,
+ UNI_VC_STATUSENQ_MSG, msg);
+ break;
+ case UNI_MSG_ADDP:
+ (void) unisig_vc_state(usp, uvp,
+ UNI_VC_ADDP_MSG, msg);
+ break;
+ case UNI_MSG_ADPA:
+ (void) unisig_vc_state(usp, uvp,
+ UNI_VC_ADDPACK_MSG, msg);
+ break;
+ case UNI_MSG_ADPR:
+ (void) unisig_vc_state(usp, uvp,
+ UNI_VC_ADDPREJ_MSG, msg);
+ break;
+ case UNI_MSG_DRPP:
+ (void) unisig_vc_state(usp, uvp,
+ UNI_VC_DROP_MSG, msg);
+ break;
+ case UNI_MSG_DRPA:
+ (void) unisig_vc_state(usp, uvp,
+ UNI_VC_DROPACK_MSG, msg);
+ break;
+ default:
+ /*
+ * Message size didn't match size received
+ */
+ err = unisig_send_status(usp, uvp, msg,
+ UNI_IE_CAUS_MTEXIST);
+ }
+
+done:
+ /*
+ * Handle message errors that require a response
+ */
+ switch(err) {
+ case EMSGSIZE:
+ /*
+ * Message size didn't match size received
+ */
+ err = unisig_send_status(usp, uvp, msg,
+ UNI_IE_CAUS_LEN);
+ break;
+ }
+
+ /*
+ * Free the incoming message (both buffer and internal format)
+ * if necessary.
+ */
+ if (msg)
+ unisig_free_msg(msg);
+ if (m)
+ KB_FREEALL(m);
+
+ return (err);
+}
diff --git a/sys/netatm/uni/unisig_msg.h b/sys/netatm/uni/unisig_msg.h
new file mode 100644
index 0000000..4be0144
--- /dev/null
+++ b/sys/netatm/uni/unisig_msg.h
@@ -0,0 +1,953 @@
+/*
+ *
+ * ===================================
+ * 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: unisig_msg.h,v 1.8 1998/08/26 23:29:23 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI 3.0/3.1 Signalling Manager
+ * ----------------------------------------
+ *
+ * Message formatting blocks
+ *
+ */
+
+#ifndef _UNI_SIG_MSG_H
+#define _UNI_SIG_MSG_H
+
+#define UNI_MSG_DISC_Q93B 0x09
+#define UNI_MSG_MIN_LEN 9
+
+/*
+ * Values for Q.2931 message type.
+ */
+#define UNI_MSG_CALP 0x02
+#define UNI_MSG_CONN 0x07
+#define UNI_MSG_CACK 0x0F
+#define UNI_MSG_SETU 0x05
+#define UNI_MSG_RLSE 0x4D
+#define UNI_MSG_RLSC 0x5A
+#define UNI_MSG_RSTR 0x46
+#define UNI_MSG_RSTA 0x4E
+#define UNI_MSG_STAT 0x7D
+#define UNI_MSG_SENQ 0x75
+#define UNI_MSG_ADDP 0x80
+#define UNI_MSG_ADPA 0x81
+#define UNI_MSG_ADPR 0x82
+#define UNI_MSG_DRPP 0x83
+#define UNI_MSG_DRPA 0x84
+
+
+/*
+ * Values for information element identifier.
+ */
+#define UNI_IE_CAUS 0x08
+#define UNI_IE_CLST 0x14
+#define UNI_IE_EPRF 0x54
+#define UNI_IE_EPST 0x55
+#define UNI_IE_AALP 0x58
+#define UNI_IE_CLRT 0x59
+#define UNI_IE_CNID 0x5A
+#define UNI_IE_QOSP 0x5C
+#define UNI_IE_BHLI 0x5D
+#define UNI_IE_BBCP 0x5E
+#define UNI_IE_BLLI 0x5F
+#define UNI_IE_BLSH 0x60
+#define UNI_IE_BNSH 0x61
+#define UNI_IE_BSDC 0x62
+#define UNI_IE_BRPI 0x63
+#define UNI_IE_CGAD 0x6C
+#define UNI_IE_CGSA 0x6D
+#define UNI_IE_CDAD 0x70
+#define UNI_IE_CDSA 0x71
+#define UNI_IE_TRNT 0x78
+#define UNI_IE_RSTI 0x79
+
+/*
+ * Masks for information element extension in bit 8
+ */
+#define UNI_IE_EXT_BIT 0x80
+#define UNI_IE_EXT_MASK 0x7F
+
+
+/*
+ * Signalling message in internal format.
+ */
+#define UNI_MSG_IE_CNT 22
+
+struct unisig_msg {
+ u_int msg_call_ref;
+ u_char msg_type;
+ u_char msg_type_flag;
+ u_char msg_type_action;
+ int msg_length;
+ struct ie_generic *msg_ie_vec[UNI_MSG_IE_CNT];
+};
+
+#define UNI_MSG_CALL_REF_RMT 0x800000
+#define UNI_MSG_CALL_REF_MASK 0x7FFFFF
+#define UNI_MSG_CALL_REF_GLOBAL 0
+#define UNI_MSG_CALL_REF_DUMMY 0x7FFFFF
+
+#define EXTRACT_CREF(x) \
+ ((x) & UNI_MSG_CALL_REF_RMT ? (x) & UNI_MSG_CALL_REF_MASK : (x) | UNI_MSG_CALL_REF_RMT)
+#define GLOBAL_CREF(x) ((x) & UNI_MSG_CALL_REF_MASK == UNI_MSG_CALL_REF_GLOBAL)
+#define DUMMY_CREF(x) ((x) & UNI_MSG_CALL_REF_MASK == UNI_MSG_CALL_REF_DUMMY)
+
+#define UNI_MSG_TYPE_FLAG_MASK 1
+#define UNI_MSG_TYPE_FLAG_SHIFT 4
+
+#define UNI_MSG_TYPE_ACT_CLEAR 0
+#define UNI_MSG_TYPE_ACT_DISC 1
+#define UNI_MSG_TYPE_ACT_RPRT 2
+#define UNI_MSG_TYPE_ACT_RSVD 3
+#define UNI_MSG_TYPE_ACT_MASK 3
+
+#define UNI_MSG_IE_AALP 0
+#define UNI_MSG_IE_CLRT 1
+#define UNI_MSG_IE_BBCP 2
+#define UNI_MSG_IE_BHLI 3
+#define UNI_MSG_IE_BLLI 4
+#define UNI_MSG_IE_CLST 5
+#define UNI_MSG_IE_CDAD 6
+#define UNI_MSG_IE_CDSA 7
+#define UNI_MSG_IE_CGAD 8
+#define UNI_MSG_IE_CGSA 9
+#define UNI_MSG_IE_CAUS 10
+#define UNI_MSG_IE_CNID 11
+#define UNI_MSG_IE_QOSP 12
+#define UNI_MSG_IE_BRPI 13
+#define UNI_MSG_IE_RSTI 14
+#define UNI_MSG_IE_BLSH 15
+#define UNI_MSG_IE_BNSH 16
+#define UNI_MSG_IE_BSDC 17
+#define UNI_MSG_IE_TRNT 18
+#define UNI_MSG_IE_EPRF 19
+#define UNI_MSG_IE_EPST 20
+#define UNI_MSG_IE_ERR 21
+
+#define msg_ie_aalp msg_ie_vec[UNI_MSG_IE_AALP]
+#define msg_ie_clrt msg_ie_vec[UNI_MSG_IE_CLRT]
+#define msg_ie_bbcp msg_ie_vec[UNI_MSG_IE_BBCP]
+#define msg_ie_bhli msg_ie_vec[UNI_MSG_IE_BHLI]
+#define msg_ie_blli msg_ie_vec[UNI_MSG_IE_BLLI]
+#define msg_ie_clst msg_ie_vec[UNI_MSG_IE_CLST]
+#define msg_ie_cdad msg_ie_vec[UNI_MSG_IE_CDAD]
+#define msg_ie_cdsa msg_ie_vec[UNI_MSG_IE_CDSA]
+#define msg_ie_cgad msg_ie_vec[UNI_MSG_IE_CGAD]
+#define msg_ie_cgsa msg_ie_vec[UNI_MSG_IE_CGSA]
+#define msg_ie_caus msg_ie_vec[UNI_MSG_IE_CAUS]
+#define msg_ie_cnid msg_ie_vec[UNI_MSG_IE_CNID]
+#define msg_ie_qosp msg_ie_vec[UNI_MSG_IE_QOSP]
+#define msg_ie_brpi msg_ie_vec[UNI_MSG_IE_BRPI]
+#define msg_ie_rsti msg_ie_vec[UNI_MSG_IE_RSTI]
+#define msg_ie_blsh msg_ie_vec[UNI_MSG_IE_BLSH]
+#define msg_ie_bnsh msg_ie_vec[UNI_MSG_IE_BNSH]
+#define msg_ie_bsdc msg_ie_vec[UNI_MSG_IE_BSDC]
+#define msg_ie_trnt msg_ie_vec[UNI_MSG_IE_TRNT]
+#define msg_ie_eprf msg_ie_vec[UNI_MSG_IE_EPRF]
+#define msg_ie_epst msg_ie_vec[UNI_MSG_IE_EPST]
+#define msg_ie_err msg_ie_vec[UNI_MSG_IE_ERR]
+
+
+/*
+ * Information element header.
+ */
+struct ie_hdr {
+ u_char ie_hdr_ident;
+ u_char ie_hdr_coding;
+ u_char ie_hdr_flag;
+ u_char ie_hdr_action;
+ int ie_hdr_length;
+ int ie_hdr_err_cause;
+ struct ie_generic *ie_hdr_next;
+};
+
+#define UNI_IE_HDR_LEN 4
+
+#define UNI_IE_CODE_CCITT 0
+#define UNI_IE_CODE_STD 3
+#define UNI_IE_CODE_MASK 3
+#define UNI_IE_CODE_SHIFT 5
+
+#define UNI_IE_FLAG_MASK 1
+#define UNI_IE_FLAG_SHIFT 4
+
+#define UNI_IE_ACT_CLEAR 0
+#define UNI_IE_ACT_DIS 1
+#define UNI_IE_ACT_RPRT 2
+#define UNI_IE_ACT_DMSGIGN 5
+#define UNI_IE_ACT_DMSGRPRT 6
+#define UNI_IE_ACT_MASK 7
+
+
+/*
+ * ATM AAL parameters information element in internal format.
+ */
+struct ie_aalp {
+ int8_t ie_aal_type;
+ union {
+ struct aal_type_1_parm {
+ u_char subtype;
+ u_char cbr_rate;
+ u_short multiplier;
+ u_char clock_recovery;
+ u_char error_correction;
+ u_char struct_data_tran;
+ u_char partial_cells;
+ } type_1;
+ struct aal_type_4_parm {
+ int32_t fwd_max_sdu;
+ int32_t bkwd_max_sdu;
+ int32_t mid_range;
+ u_char mode;
+ u_char sscs_type;
+ } type_4;
+ struct aal_type_5_parm {
+ int32_t fwd_max_sdu;
+ int32_t bkwd_max_sdu;
+ u_char mode;
+ u_char sscs_type;
+ } type_5;
+ struct user_aal_type {
+ u_char aal_info[4];
+ } type_user;
+ } aal_u;
+};
+
+#define UNI_IE_AALP_AT_AAL1 1
+#define UNI_IE_AALP_AT_AAL3 3
+#define UNI_IE_AALP_AT_AAL5 5
+#define UNI_IE_AALP_AT_AALU 16
+
+#define UNI_IE_AALP_A1_ST_NULL 0
+#define UNI_IE_AALP_A1_ST_VCE 1
+#define UNI_IE_AALP_A1_ST_SCE 2
+#define UNI_IE_AALP_A1_ST_ACE 3
+#define UNI_IE_AALP_A1_ST_HQA 4
+#define UNI_IE_AALP_A1_ST_VID 5
+
+#define UNI_IE_AALP_A1_CB_64 1
+#define UNI_IE_AALP_A1_CB_DS1 4
+#define UNI_IE_AALP_A1_CB_DS2 5
+#define UNI_IE_AALP_A1_CB_32064 6
+#define UNI_IE_AALP_A1_CB_DS3 7
+#define UNI_IE_AALP_A1_CB_97728 8
+#define UNI_IE_AALP_A1_CB_E1 16
+#define UNI_IE_AALP_A1_CB_E2 17
+#define UNI_IE_AALP_A1_CB_E3 18
+#define UNI_IE_AALP_A1_CB_139264 19
+#define UNI_IE_AALP_A1_CB_N64 64
+
+#define UNI_IE_AALP_A1_CR_NULL 0
+#define UNI_IE_AALP_A1_CR_SRTS 1
+#define UNI_IE_AALP_A1_CR_ACR 2
+
+#define UNI_IE_AALP_A1_EC_NULL 0
+#define UNI_IE_AALP_A1_EC_FEC 1
+
+#define UNI_IE_AALP_A1_SD_NULL 0
+#define UNI_IE_AALP_A1_SD_SDT 1
+
+#define UNI_IE_AALP_A3_R_MASK 1023
+#define UNI_IE_AALP_A3_R_SHIFT 16
+
+#define UNI_IE_AALP_A5_M_MSG 1
+#define UNI_IE_AALP_A5_M_STR 2
+
+#define UNI_IE_AALP_A5_ST_NULL 0
+#define UNI_IE_AALP_A5_ST_AO 1
+#define UNI_IE_AALP_A5_ST_NAO 2
+#define UNI_IE_AALP_A5_ST_FR 4
+
+
+/*
+ * ATM user cell rate information element in internal format.
+ */
+struct ie_clrt {
+ int32_t ie_fwd_peak;
+ int32_t ie_bkwd_peak;
+ int32_t ie_fwd_peak_01;
+ int32_t ie_bkwd_peak_01;
+ int32_t ie_fwd_sust;
+ int32_t ie_bkwd_sust;
+ int32_t ie_fwd_sust_01;
+ int32_t ie_bkwd_sust_01;
+ int32_t ie_fwd_burst;
+ int32_t ie_bkwd_burst;
+ int32_t ie_fwd_burst_01;
+ int32_t ie_bkwd_burst_01;
+ int8_t ie_best_effort;
+ int8_t ie_tm_options;
+};
+
+#define UNI_IE_CLRT_FWD_PEAK_ID 130
+#define UNI_IE_CLRT_BKWD_PEAK_ID 131
+#define UNI_IE_CLRT_FWD_PEAK_01_ID 132
+#define UNI_IE_CLRT_BKWD_PEAK_01_ID 133
+#define UNI_IE_CLRT_FWD_SUST_ID 136
+#define UNI_IE_CLRT_BKWD_SUST_ID 137
+#define UNI_IE_CLRT_FWD_SUST_01_ID 144
+#define UNI_IE_CLRT_BKWD_SUST_01_ID 145
+#define UNI_IE_CLRT_FWD_BURST_ID 160
+#define UNI_IE_CLRT_BKWD_BURST_ID 161
+#define UNI_IE_CLRT_FWD_BURST_01_ID 176
+#define UNI_IE_CLRT_BKWD_BURST_01_ID 177
+#define UNI_IE_CLRT_BEST_EFFORT_ID 190
+#define UNI_IE_CLRT_TM_OPTIONS_ID 191
+
+#define UNI_IE_CLRT_TM_FWD_TAG 0x01
+#define UNI_IE_CLRT_TM_BKWD_TAG 0x02
+
+
+/*
+ * Broadband bearer capability information element in internal format.
+ */
+struct ie_bbcp {
+ int8_t ie_bearer_class;
+ int8_t ie_traffic_type;
+ int8_t ie_timing_req;
+ int8_t ie_clipping;
+ int8_t ie_conn_config;
+};
+
+
+#define UNI_IE_BBCP_BC_BCOB_A 1
+#define UNI_IE_BBCP_BC_BCOB_C 3
+#define UNI_IE_BBCP_BC_BCOB_X 16
+#define UNI_IE_BBCP_BC_MASK 0x1F
+
+#define UNI_IE_BBCP_TT_NIND 0
+#define UNI_IE_BBCP_TT_CBR 1
+#define UNI_IE_BBCP_TT_VBR 2
+#define UNI_IE_BBCP_TT_MASK 3
+#define UNI_IE_BBCP_TT_SHIFT 2
+
+#define UNI_IE_BBCP_TR_NIND 0
+#define UNI_IE_BBCP_TR_EER 1
+#define UNI_IE_BBCP_TR_EENR 2
+#define UNI_IE_BBCP_TR_RSVD 3
+#define UNI_IE_BBCP_TR_MASK 3
+
+#define UNI_IE_BBCP_SC_NSUS 0
+#define UNI_IE_BBCP_SC_SUS 1
+#define UNI_IE_BBCP_SC_MASK 3
+#define UNI_IE_BBCP_SC_SHIFT 5
+
+#define UNI_IE_BBCP_CC_PP 0
+#define UNI_IE_BBCP_CC_PM 1
+#define UNI_IE_BBCP_CC_MASK 3
+
+
+/*
+ * Broadband high layer information information element in internal
+ * format.
+ */
+struct ie_bhli {
+ int8_t ie_type;
+ u_char ie_info[8];
+};
+
+#define UNI_IE_BHLI_TYPE_ISO 0
+#define UNI_IE_BHLI_TYPE_USER 1
+#define UNI_IE_BHLI_TYPE_HLP 2
+#define UNI_IE_BHLI_TYPE_VSA 3
+
+#define UNI_IE_BHLI_HLP_LEN 4
+#define UNI_IE_BHLI_VSA_LEN 7
+
+
+/*
+ * Broadband low-layer information information element in internal
+ * format.
+ */
+struct ie_blli {
+ int8_t ie_l1_id;
+ int8_t ie_l2_id;
+ int8_t ie_l2_mode;
+ int8_t ie_l2_q933_use;
+ int8_t ie_l2_window;
+ int8_t ie_l2_user_proto;
+ int8_t ie_l3_id;
+ int8_t ie_l3_mode;
+ int8_t ie_l3_packet_size;
+ int8_t ie_l3_window;
+ int8_t ie_l3_user_proto;
+ int16_t ie_l3_ipi;
+ int8_t ie_l3_snap_id;
+ u_char ie_l3_oui[3];
+ u_char ie_l3_pid[2];
+};
+
+#define UNI_IE_BLLI_L1_ID 1
+#define UNI_IE_BLLI_L2_ID 2
+#define UNI_IE_BLLI_L3_ID 3
+#define UNI_IE_BLLI_LID_MASK 3
+#define UNI_IE_BLLI_LID_SHIFT 5
+#define UNI_IE_BLLI_LP_MASK 31
+
+#define UNI_IE_BLLI_L2P_ISO1745 1
+#define UNI_IE_BLLI_L2P_Q921 2
+#define UNI_IE_BLLI_L2P_X25L 6
+#define UNI_IE_BLLI_L2P_X25M 7
+#define UNI_IE_BLLI_L2P_LAPB 8
+#define UNI_IE_BLLI_L2P_HDLC1 9
+#define UNI_IE_BLLI_L2P_HDLC2 10
+#define UNI_IE_BLLI_L2P_HDLC3 11
+#define UNI_IE_BLLI_L2P_LLC 12
+#define UNI_IE_BLLI_L2P_X75 13
+#define UNI_IE_BLLI_L2P_Q922 14
+#define UNI_IE_BLLI_L2P_USER 16
+#define UNI_IE_BLLI_L2P_ISO7776 17
+
+#define UNI_IE_BLLI_L2MODE_NORM 1
+#define UNI_IE_BLLI_L2MODE_EXT 2
+#define UNI_IE_BLLI_L2MODE_SHIFT 5
+#define UNI_IE_BLLI_L2MODE_MASK 3
+
+#define UNI_IE_BLLI_Q933_ALT 0
+
+#define UNI_IE_BLLI_L3P_X25 6
+#define UNI_IE_BLLI_L3P_ISO8208 7
+#define UNI_IE_BLLI_L3P_ISO8878 8
+#define UNI_IE_BLLI_L3P_ISO8473 9
+#define UNI_IE_BLLI_L3P_T70 10
+#define UNI_IE_BLLI_L3P_ISO9577 11
+#define UNI_IE_BLLI_L3P_USER 16
+
+#define UNI_IE_BLLI_L3MODE_NORM 1
+#define UNI_IE_BLLI_L3MODE_EXT 2
+#define UNI_IE_BLLI_L3MODE_SHIFT 5
+#define UNI_IE_BLLI_L3MODE_MASK 3
+
+#define UNI_IE_BLLI_L3PS_16 4
+#define UNI_IE_BLLI_L3PS_32 5
+#define UNI_IE_BLLI_L3PS_64 6
+#define UNI_IE_BLLI_L3PS_128 7
+#define UNI_IE_BLLI_L3PS_256 8
+#define UNI_IE_BLLI_L3PS_512 9
+#define UNI_IE_BLLI_L3PS_1024 10
+#define UNI_IE_BLLI_L3PS_2048 11
+#define UNI_IE_BLLI_L3PS_4096 12
+#define UNI_IE_BLLI_L3PS_MASK 15
+
+#define UNI_IE_BLLI_L3IPI_SHIFT 6
+#define UNI_IE_BLLI_L3IPI_SNAP 0x80
+
+
+/*
+ * Call state information element in internal format.
+ */
+struct ie_clst {
+ int8_t ie_state;
+};
+
+#define UNI_IE_CLST_STATE_U0 0
+#define UNI_IE_CLST_STATE_U1 1
+#define UNI_IE_CLST_STATE_U3 3
+#define UNI_IE_CLST_STATE_U6 6
+#define UNI_IE_CLST_STATE_U8 8
+#define UNI_IE_CLST_STATE_U9 9
+#define UNI_IE_CLST_STATE_U10 10
+#define UNI_IE_CLST_STATE_U11 11
+#define UNI_IE_CLST_STATE_U12 12
+
+#define UNI_IE_CLST_STATE_N0 0
+#define UNI_IE_CLST_STATE_N1 1
+#define UNI_IE_CLST_STATE_N3 3
+#define UNI_IE_CLST_STATE_N6 6
+#define UNI_IE_CLST_STATE_N8 8
+#define UNI_IE_CLST_STATE_N9 9
+#define UNI_IE_CLST_STATE_N10 10
+#define UNI_IE_CLST_STATE_N11 11
+#define UNI_IE_CLST_STATE_N12 12
+
+#define UNI_IE_CLST_GLBL_REST0 0x00
+#define UNI_IE_CLST_GLBL_REST1 0x3d
+#define UNI_IE_CLST_GLBL_REST2 0x3e
+
+#define UNI_IE_CLST_STATE_MASK 0x3f
+
+
+/*
+ * Called party number information element in internal format.
+ */
+struct ie_cdad {
+ int8_t ie_type;
+ int8_t ie_plan;
+ Atm_addr ie_addr;
+};
+
+#define UNI_IE_CDAD_TYPE_UNK 0
+#define UNI_IE_CDAD_TYPE_INTL 1
+#define UNI_IE_CDAD_TYPE_MASK 7
+#define UNI_IE_CDAD_TYPE_SHIFT 4
+
+#define UNI_IE_CDAD_PLAN_E164 1
+#define UNI_IE_CDAD_PLAN_NSAP 2
+#define UNI_IE_CDAD_PLAN_MASK 15
+
+
+/*
+ * Called party subaddress information element in internal format.
+ */
+struct ie_cdsa {
+ Atm_addr ie_addr;
+};
+
+#define UNI_IE_CDSA_TYPE_NSAP 0
+#define UNI_IE_CDSA_TYPE_AESA 1
+#define UNI_IE_CDSA_TYPE_MASK 7
+#define UNI_IE_CDSA_TYPE_SHIFT 4
+
+
+/*
+ * Calling party number information element in internal format.
+ */
+struct ie_cgad {
+ int8_t ie_type;
+ int8_t ie_plan;
+ int8_t ie_pres_ind;
+ int8_t ie_screen_ind;
+ Atm_addr ie_addr;
+};
+
+#define UNI_IE_CGAD_TYPE_UNK 0
+#define UNI_IE_CGAD_TYPE_INTL 1
+#define UNI_IE_CGAD_TYPE_MASK 7
+#define UNI_IE_CGAD_TYPE_SHIFT 4
+
+#define UNI_IE_CGAD_PLAN_E164 1
+#define UNI_IE_CGAD_PLAN_NSAP 2
+#define UNI_IE_CGAD_PLAN_MASK 15
+
+#define UNI_IE_CGAD_PRES_ALLOW 0
+#define UNI_IE_CGAD_PRES_RSTR 1
+#define UNI_IE_CGAD_PRES_NNA 2
+#define UNI_IE_CGAD_PRES_RSVD 3
+#define UNI_IE_CGAD_PRES_MASK 3
+#define UNI_IE_CGAD_PRES_SHIFT 5
+
+#define UNI_IE_CGAD_SCR_UNS 0
+#define UNI_IE_CGAD_SCR_UVP 1
+#define UNI_IE_CGAD_SCR_UVF 2
+#define UNI_IE_CGAD_SCR_NET 3
+#define UNI_IE_CGAD_SCR_MASK 3
+
+
+/*
+ * Calling party subaddress information element in internal format.
+ */
+struct ie_cgsa {
+ Atm_addr ie_addr;
+};
+
+#define UNI_IE_CGSA_TYPE_NSAP 0
+#define UNI_IE_CGSA_TYPE_AESA 1
+#define UNI_IE_CGSA_TYPE_MASK 7
+#define UNI_IE_CGSA_TYPE_SHIFT 4
+
+
+/*
+ * Cause information element in internal format.
+ */
+#define UNI_IE_CAUS_MAX_ID 24
+#define UNI_IE_CAUS_MAX_QOS_SUB 24
+struct ie_caus {
+ int8_t ie_loc;
+ int8_t ie_cause;
+ int8_t ie_diag_len;
+ u_int8_t ie_diagnostic[24];
+};
+
+#define UNI_IE_CAUS_LOC_USER 0
+#define UNI_IE_CAUS_LOC_PRI_LCL 1
+#define UNI_IE_CAUS_LOC_PUB_LCL 2
+#define UNI_IE_CAUS_LOC_TRANSIT 3
+#define UNI_IE_CAUS_LOC_PUB_RMT 4
+#define UNI_IE_CAUS_LOC_PRI_RMT 5
+#define UNI_IE_CAUS_LOC_INTL 7
+#define UNI_IE_CAUS_LOC_BEYOND 10
+#define UNI_IE_CAUS_LOC_MASK 15
+
+#define UNI_IE_CAUS_UN_NS_SHIFT 3
+#define UNI_IE_CAUS_UN_NS_MASK 1
+
+#define UNI_IE_CAUS_UN_NA_SHIFT 2
+#define UNI_IE_CAUS_UN_NA_MASK 1
+
+#define UNI_IE_CAUS_UN_CAU_MASK 3
+
+#define UNI_IE_CAUS_RR_USER 0
+#define UNI_IE_CAUS_RR_IE 1
+#define UNI_IE_CAUS_RR_INSUFF 2
+#define UNI_IE_CAUS_RR_SHIFT 2
+#define UNI_IE_CAUS_RR_MASK 31
+
+#define UNI_IE_CAUS_RC_UNK 0
+#define UNI_IE_CAUS_RC_PERM 1
+#define UNI_IE_CAUS_RC_TRANS 2
+#define UNI_IE_CAUS_RC_MASK 3
+
+/*
+ * Cause codes from UNI 3.0, section 5.4.5.15
+ */
+#define UNI_IE_CAUS_UNO 1 /* Unallocated number */
+#define UNI_IE_CAUS_NOTROUTE 2 /* No route to transit net */
+#define UNI_IE_CAUS_NODROUTE 3 /* No route to destination */
+#define UNI_IE_CAUS_BAD_VCC 10 /* VPI/VCI unacceptable */
+#define UNI_IE_CAUS_NORM 16 /* Normal call clearing */
+#define UNI_IE_CAUS_BUSY 17 /* User busy */
+#define UNI_IE_CAUS_NORSP 18 /* No user responding */
+#define UNI_IE_CAUS_REJECT 21 /* Call rejected */
+#define UNI_IE_CAUS_CHANGED 22 /* Number changed */
+#define UNI_IE_CAUS_CLIR 23 /* User rejects CLIR */
+#define UNI_IE_CAUS_DORDER 27 /* Dest out of order */
+#define UNI_IE_CAUS_INVNO 28 /* Invalid number format */
+#define UNI_IE_CAUS_SENQ 30 /* Rsp to Status Enquiry */
+#define UNI_IE_CAUS_NORM_UNSP 31 /* Normal, unspecified */
+#define UNI_IE_CAUS_NA_VCC 35 /* VCC not available */
+#define UNI_IE_CAUS_ASSIGN_VCC 36 /* VPCI/VCI assignment failure */
+#define UNI_IE_CAUS_NORDER 38 /* Network out of order */
+#define UNI_IE_CAUS_TEMP 41 /* Temporary failure */
+#define UNI_IE_CAUS_DISCARD 43 /* Access info discarded */
+#define UNI_IE_CAUS_NO_VCC 45 /* No VPI/VCI available */
+#define UNI_IE_CAUS_UNAVAIL 47 /* Resource unavailable */
+#define UNI_IE_CAUS_NO_QOS 49 /* QoS unavailable */
+#define UNI_IE_CAUS_NO_CR 51 /* User cell rate not avail */
+#define UNI_IE_CAUS_NO_BC 57 /* Bearer capability not auth */
+#define UNI_IE_CAUS_NA_BC 58 /* Bearer capability n/a */
+#define UNI_IE_CAUS_SERVICE 63 /* Service or opt not avail */
+#define UNI_IE_CAUS_NI_BC 65 /* Bearer cap not implemented */
+#define UNI_IE_CAUS_COMB 73 /* Unsupported combination */
+#define UNI_IE_CAUS_CREF 81 /* Invalid call reference */
+#define UNI_IE_CAUS_CEXIST 82 /* Channel does not exist */
+#define UNI_IE_CAUS_IDEST 88 /* Incompatible destination */
+#define UNI_IE_CAUS_ENDPT 89 /* Invalid endpoint reference */
+#define UNI_IE_CAUS_TRNET 91 /* Invalid transit net */
+#define UNI_IE_CAUS_APPEND 92 /* Too many pending add party */
+#define UNI_IE_CAUS_UAAL 93 /* AAL parms can't be supp */
+#define UNI_IE_CAUS_MISSING 96 /* Mandatory IE missing */
+#define UNI_IE_CAUS_MTEXIST 97 /* Message type nonexistent */
+#define UNI_IE_CAUS_IEEXIST 99 /* IE type nonexistent */
+#define UNI_IE_CAUS_IECONTENT 100 /* IE content invalid */
+#define UNI_IE_CAUS_STATE 101 /* Message incomp with state */
+#define UNI_IE_CAUS_TIMER 102 /* Recovery on timer expire */
+#define UNI_IE_CAUS_LEN 104 /* Incorrect message length */
+#define UNI_IE_CAUS_PROTO 111 /* Protocol error */
+
+
+/*
+ * Connection identifier information element in internal format.
+ */
+struct ie_cnid {
+ int8_t ie_vp_sig;
+ int8_t ie_pref_excl;
+ u_short ie_vpci;
+ u_short ie_vci;
+};
+
+#define UNI_IE_CNID_VPSIG_MASK 3
+#define UNI_IE_CNID_VPSIG_SHIFT 3
+#define UNI_IE_CNID_PREX_MASK 7
+
+#define UNI_IE_CNID_MIN_VCI 32
+
+
+/*
+ * Quality of service parameter information element in internal format.
+ */
+struct ie_qosp {
+ int8_t ie_fwd_class;
+ int8_t ie_bkwd_class;
+};
+
+#define UNI_IE_QOSP_FWD_CLASS_0 0
+#define UNI_IE_QOSP_FWD_CLASS_1 1
+#define UNI_IE_QOSP_FWD_CLASS_2 2
+#define UNI_IE_QOSP_FWD_CLASS_3 3
+#define UNI_IE_QOSP_FWD_CLASS_4 4
+
+#define UNI_IE_QOSP_BKWD_CLASS_0 0
+#define UNI_IE_QOSP_BKWD_CLASS_1 1
+#define UNI_IE_QOSP_BKWD_CLASS_2 2
+#define UNI_IE_QOSP_BKWD_CLASS_3 3
+#define UNI_IE_QOSP_BKWD_CLASS_4 4
+
+
+/*
+ * Broadband repeat indicator information element in internal format.
+ */
+struct ie_brpi {
+ int8_t ie_ind;
+};
+
+#define UNI_IE_BRPI_PRI_LIST 2
+#define UNI_IE_BRPI_IND_MASK 15
+
+
+/*
+ * Restart indicator information element in internal format.
+ */
+struct ie_rsti {
+ int8_t ie_class;
+};
+
+#define UNI_IE_RSTI_IND_VC 0
+#define UNI_IE_RSTI_ALL_VC 2
+#define UNI_IE_RSTI_CLASS_MASK 3
+
+
+/*
+ * Broadband locking shift information element in internal format.
+ */
+struct ie_blsh {
+ int8_t ie_dummy;
+};
+
+
+/*
+ * Broadband non-locking shift information element in internal format.
+ */
+struct ie_bnsh {
+ int8_t ie_dummy;
+};
+
+
+/*
+ * Broadband sending complete information element in internal format.
+ */
+struct ie_bsdc {
+ int8_t ie_ind;
+};
+
+#define UNI_IE_BSDC_IND 0x21
+
+
+/*
+ * Transit net selection information element in internal format.
+ */
+struct ie_trnt {
+ int8_t ie_id_type;
+ int8_t ie_id_plan;
+ u_char ie_id_len;
+ u_char ie_id[4];
+};
+
+#define UNI_IE_TRNT_IDT_MASK 7
+#define UNI_IE_TRNT_IDT_SHIFT 4
+#define UNI_IE_TRNT_IDP_MASK 15
+
+#define UNI_IE_TRNT_IDT_NATL 2
+#define UNI_IE_TRNT_IDP_CIC 1
+
+
+/*
+ * Endpoint reference information element in internal format.
+ */
+struct ie_eprf {
+ int8_t ie_type;
+ int16_t ie_id;
+};
+
+#define UNI_IE_EPRF_LDI 0
+
+
+/*
+ * Endpoint state information element in internal format.
+ */
+struct ie_epst {
+ int8_t ie_state;
+};
+
+#define UNI_IE_EPST_NULL 0
+#define UNI_IE_EPST_API 1
+#define UNI_IE_EPST_APR 6
+#define UNI_IE_EPST_DPI 11
+#define UNI_IE_EPST_DPR 12
+#define UNI_IE_EPST_ACTIVE 10
+#define UNI_IE_EPST_STATE_MASK 0x3F
+
+
+/*
+ * Generic information element
+ */
+struct ie_generic {
+ struct ie_hdr ie_hdr;
+ union {
+ struct ie_aalp ie_aalp;
+ struct ie_clrt ie_clrt;
+ struct ie_bbcp ie_bbcp;
+ struct ie_bhli ie_bhli;
+ struct ie_blli ie_blli;
+ struct ie_clst ie_clst;
+ struct ie_cdad ie_cdad;
+ struct ie_cdsa ie_cdsa;
+ struct ie_cgad ie_cgad;
+ struct ie_cgsa ie_cgsa;
+ struct ie_caus ie_caus;
+ struct ie_cnid ie_cnid;
+ struct ie_qosp ie_qosp;
+ struct ie_brpi ie_brpi;
+ struct ie_rsti ie_rsti;
+ struct ie_blsh ie_blsh;
+ struct ie_bnsh ie_bnsh;
+ struct ie_bsdc ie_bsdc;
+ struct ie_trnt ie_trnt;
+ struct ie_eprf ie_eprf;
+ struct ie_epst ie_epst;
+ } ie_u;
+};
+
+#define ie_ident ie_hdr.ie_hdr_ident
+#define ie_coding ie_hdr.ie_hdr_coding
+#define ie_flag ie_hdr.ie_hdr_flag
+#define ie_action ie_hdr.ie_hdr_action
+#define ie_length ie_hdr.ie_hdr_length
+#define ie_err_cause ie_hdr.ie_hdr_err_cause
+#define ie_next ie_hdr.ie_hdr_next
+
+#define ie_aalp_aal_type ie_u.ie_aalp.ie_aal_type
+#define ie_aalp_1_subtype ie_u.ie_aalp.aal_u.type_1.subtype
+#define ie_aalp_1_cbr_rate ie_u.ie_aalp.aal_u.type_1.cbr_rate
+#define ie_aalp_1_multiplier ie_u.ie_aalp.aal_u.type_1.multiplier
+#define ie_aalp_1_clock_recovery ie_u.ie_aalp.aal_u.type_1.clock_recovery
+#define ie_aalp_1_error_correction ie_u.ie_aalp.aal_u.type_1.error_correction
+#define ie_aalp_1_struct_data_tran ie_u.ie_aalp.aal_u.type_1.struct_data_tran
+#define ie_aalp_1_partial_cells ie_u.ie_aalp.aal_u.type_1.partial_cells
+
+#define ie_aalp_4_fwd_max_sdu ie_u.ie_aalp.aal_u.type_4.fwd_max_sdu
+#define ie_aalp_4_bkwd_max_sdu ie_u.ie_aalp.aal_u.type_4.bkwd_max_sdu
+#define ie_aalp_4_mid_range ie_u.ie_aalp.aal_u.type_4.mid_range
+#define ie_aalp_4_mode ie_u.ie_aalp.aal_u.type_4.mode
+#define ie_aalp_4_sscs_type ie_u.ie_aalp.aal_u.type_4.sscs_type
+
+#define ie_aalp_5_fwd_max_sdu ie_u.ie_aalp.aal_u.type_5.fwd_max_sdu
+#define ie_aalp_5_bkwd_max_sdu ie_u.ie_aalp.aal_u.type_5.bkwd_max_sdu
+#define ie_aalp_5_mode ie_u.ie_aalp.aal_u.type_5.mode
+#define ie_aalp_5_sscs_type ie_u.ie_aalp.aal_u.type_5.sscs_type
+#define ie_aalp_user_info ie_u.ie_aalp.aal_u.type_user.aal_info
+
+#define ie_clrt_fwd_peak ie_u.ie_clrt.ie_fwd_peak
+#define ie_clrt_bkwd_peak ie_u.ie_clrt.ie_bkwd_peak
+#define ie_clrt_fwd_peak_01 ie_u.ie_clrt.ie_fwd_peak_01
+#define ie_clrt_bkwd_peak_01 ie_u.ie_clrt.ie_bkwd_peak_01
+#define ie_clrt_fwd_sust ie_u.ie_clrt.ie_fwd_sust
+#define ie_clrt_bkwd_sust ie_u.ie_clrt.ie_bkwd_sust
+#define ie_clrt_fwd_sust_01 ie_u.ie_clrt.ie_fwd_sust_01
+#define ie_clrt_bkwd_sust_01 ie_u.ie_clrt.ie_bkwd_sust_01
+#define ie_clrt_fwd_burst ie_u.ie_clrt.ie_fwd_burst
+#define ie_clrt_bkwd_burst ie_u.ie_clrt.ie_bkwd_burst
+#define ie_clrt_fwd_burst_01 ie_u.ie_clrt.ie_fwd_burst_01
+#define ie_clrt_bkwd_burst_01 ie_u.ie_clrt.ie_bkwd_burst_01
+#define ie_clrt_best_effort ie_u.ie_clrt.ie_best_effort
+#define ie_clrt_tm_options ie_u.ie_clrt.ie_tm_options
+
+#define ie_bbcp_bearer_class ie_u.ie_bbcp.ie_bearer_class
+#define ie_bbcp_traffic_type ie_u.ie_bbcp.ie_traffic_type
+#define ie_bbcp_timing_req ie_u.ie_bbcp.ie_timing_req
+#define ie_bbcp_clipping ie_u.ie_bbcp.ie_clipping
+#define ie_bbcp_conn_config ie_u.ie_bbcp.ie_conn_config
+
+#define ie_bhli_type ie_u.ie_bhli.ie_type
+#define ie_bhli_info ie_u.ie_bhli.ie_info
+
+#define ie_blli_l1_id ie_u.ie_blli.ie_l1_id
+#define ie_blli_l2_id ie_u.ie_blli.ie_l2_id
+#define ie_blli_l2_mode ie_u.ie_blli.ie_l2_mode
+#define ie_blli_l2_q933_use ie_u.ie_blli.ie_l2_q933_use
+#define ie_blli_l2_window ie_u.ie_blli.ie_l2_window
+#define ie_blli_l2_user_proto ie_u.ie_blli.ie_l2_user_proto
+#define ie_blli_l3_id ie_u.ie_blli.ie_l3_id
+#define ie_blli_l3_mode ie_u.ie_blli.ie_l3_mode
+#define ie_blli_l3_packet_size ie_u.ie_blli.ie_l3_packet_size
+#define ie_blli_l3_window ie_u.ie_blli.ie_l3_window
+#define ie_blli_l3_user_proto ie_u.ie_blli.ie_l3_user_proto
+#define ie_blli_l3_ipi ie_u.ie_blli.ie_l3_ipi
+#define ie_blli_l3_snap_id ie_u.ie_blli.ie_l3_snap_id
+#define ie_blli_l3_oui ie_u.ie_blli.ie_l3_oui
+#define ie_blli_l3_pid ie_u.ie_blli.ie_l3_pid
+
+#define ie_clst_state ie_u.ie_clst.ie_state
+
+#define ie_cdad_type ie_u.ie_cdad.ie_type
+#define ie_cdad_plan ie_u.ie_cdad.ie_plan
+#define ie_cdad_addr ie_u.ie_cdad.ie_addr
+
+#define ie_cdsa_addr ie_u.ie_cdsa.ie_addr
+
+#define ie_cgad_type ie_u.ie_cgad.ie_type
+#define ie_cgad_plan ie_u.ie_cgad.ie_plan
+#define ie_cgad_pres_ind ie_u.ie_cgad.ie_pres_ind
+#define ie_cgad_screen_ind ie_u.ie_cgad.ie_screen_ind
+#define ie_cgad_addr ie_u.ie_cgad.ie_addr
+
+#define ie_cgsa_addr ie_u.ie_cgsa.ie_addr
+
+#define ie_caus_loc ie_u.ie_caus.ie_loc
+#define ie_caus_cause ie_u.ie_caus.ie_cause
+#define ie_caus_diag_len ie_u.ie_caus.ie_diag_len
+#define ie_caus_diagnostic ie_u.ie_caus.ie_diagnostic
+
+#define ie_cnid_vp_sig ie_u.ie_cnid.ie_vp_sig
+#define ie_cnid_pref_excl ie_u.ie_cnid.ie_pref_excl
+#define ie_cnid_vpci ie_u.ie_cnid.ie_vpci
+#define ie_cnid_vci ie_u.ie_cnid.ie_vci
+
+#define ie_qosp_fwd_class ie_u.ie_qosp.ie_fwd_class
+#define ie_qosp_bkwd_class ie_u.ie_qosp.ie_bkwd_class
+
+#define ie_brpi_ind ie_u.ie_brpi.ie_ind
+
+#define ie_rsti_class ie_u.ie_rsti.ie_class
+
+#define ie_bsdc_ind ie_u.ie_bsdc.ie_ind
+
+#define ie_trnt_id_type ie_u.ie_trnt.ie_id_type
+#define ie_trnt_id_plan ie_u.ie_trnt.ie_id_plan
+#define ie_trnt_id_len ie_u.ie_trnt.ie_id_len
+#define ie_trnt_id ie_u.ie_trnt.ie_id
+
+#define ie_eprf_type ie_u.ie_eprf.ie_type
+#define ie_eprf_id ie_u.ie_eprf.ie_id
+
+#define ie_epst_state ie_u.ie_epst.ie_state
+
+/*
+ * Macro to add an IE to the end of a list of IEs
+ */
+#define MSG_IE_ADD(m, i, ind) \
+ if (m->msg_ie_vec[ind]) { \
+ struct ie_generic *_iep = msg->msg_ie_vec[ind]; \
+ while (_iep->ie_next) { \
+ _iep = _iep->ie_next; \
+ } \
+ _iep->ie_next = i; \
+ } else { \
+ m->msg_ie_vec[ind] = i; \
+ }
+
+#endif /* _UNI_SIG_MSG_H */
diff --git a/sys/netatm/uni/unisig_print.c b/sys/netatm/uni/unisig_print.c
new file mode 100644
index 0000000..f335ce4
--- /dev/null
+++ b/sys/netatm/uni/unisig_print.c
@@ -0,0 +1,877 @@
+/*
+ *
+ * ===================================
+ * 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: unisig_print.c,v 1.9 1998/08/26 23:29:23 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI 3.0/3.1 Signalling Manager
+ * ----------------------------------------
+ *
+ * Print Q.2931 messages
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: unisig_print.c,v 1.9 1998/08/26 23:29:23 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/unisig.h>
+#include <netatm/uni/unisig_var.h>
+#include <netatm/uni/unisig_msg.h>
+#include <netatm/uni/unisig_print.h>
+
+
+/*
+ * Local declarations
+ */
+struct type_name {
+ char *name;
+ u_char type;
+};
+
+
+/*
+ * Local functions
+ */
+static char * find_type __P((struct type_name *, u_char));
+static void usp_print_atm_addr __P((Atm_addr *));
+static void usp_print_ie __P((struct ie_generic *));
+static void usp_print_ie_aalp __P((struct ie_generic *));
+static void usp_print_ie_clrt __P((struct ie_generic *));
+static void usp_print_ie_bbcp __P((struct ie_generic *));
+static void usp_print_ie_bhli __P((struct ie_generic *));
+static void usp_print_ie_blli __P((struct ie_generic *));
+static void usp_print_ie_clst __P((struct ie_generic *));
+static void usp_print_ie_cdad __P((struct ie_generic *));
+static void usp_print_ie_cdsa __P((struct ie_generic *));
+static void usp_print_ie_cgad __P((struct ie_generic *));
+static void usp_print_ie_cgsa __P((struct ie_generic *));
+static void usp_print_ie_caus __P((struct ie_generic *));
+static void usp_print_ie_cnid __P((struct ie_generic *));
+static void usp_print_ie_qosp __P((struct ie_generic *));
+static void usp_print_ie_brpi __P((struct ie_generic *));
+static void usp_print_ie_rsti __P((struct ie_generic *));
+static void usp_print_ie_blsh __P((struct ie_generic *));
+static void usp_print_ie_bnsh __P((struct ie_generic *));
+static void usp_print_ie_bsdc __P((struct ie_generic *));
+static void usp_print_ie_trnt __P((struct ie_generic *));
+static void usp_print_ie_eprf __P((struct ie_generic *));
+static void usp_print_ie_epst __P((struct ie_generic *));
+
+
+/*
+ * Values for Q.2931 message type.
+ */
+static struct type_name msg_types[] = {
+ { "Call proceeding", 0x02 },
+ { "Connect", 0x07 },
+ { "Connect ACK", 0x0F },
+ { "Setup", 0x05 },
+ { "Release", 0x4D },
+ { "Release complete", 0x5A },
+ { "Restart", 0x46 },
+ { "Restart ACK", 0x4E },
+ { "Status", 0x7D },
+ { "Status enquiry", 0x75 },
+ { "Add party", 0x80 },
+ { "Add party ACK", 0x81 },
+ { "Add party reject", 0x82 },
+ { "Drop party", 0x83 },
+ { "Drop party ACK", 0x84 },
+ {0, 0}
+};
+
+
+/*
+ * Values for information element identifier.
+ */
+static struct type_name ie_types[] = {
+ { "Cause", 0x08 },
+ { "Call state", 0x14 },
+ { "Endpoint reference", 0x54 },
+ { "Endpoint state", 0x55 },
+ { "ATM AAL parameters", 0x58 },
+ { "ATM user cell rate", 0x59 },
+ { "Connection ID", 0x5A },
+ { "QoS parameter", 0x5C },
+ { "Broadband high layer info", 0x5D },
+ { "Broadband bearer capability", 0x5E },
+ { "Broadband low layer info", 0x5F },
+ { "Broadband locking shift", 0x60 },
+ { "Broadband non-locking shift", 0x61 },
+ { "Broadband sending complete", 0x62 },
+ { "Broadband repeat indicator", 0x63 },
+ { "Calling party number", 0x6C },
+ { "Calling party subaddress", 0x6D },
+ { "Called party number", 0x70 },
+ { "Called party subaddress", 0x71 },
+ { "Transit net selection", 0x78 },
+ { "Restart indicator", 0x79 },
+ { 0, 0 }
+};
+
+
+/*
+ * Search a name - type translation table
+ *
+ * Arguments:
+ * tbl a pointer to the table to search
+ * type the type to look for
+ *
+ * Returns:
+ * name a pointer to a character string with the name
+ *
+ */
+static char *
+find_type(tbl, type)
+ struct type_name *tbl;
+ u_char type;
+{
+ while (type != tbl->type && tbl->name)
+ tbl++;
+
+ if (tbl->name)
+ return(tbl->name);
+ else
+ return("-");
+}
+
+
+/*
+ * Print an ATM address
+ *
+ * Arguments:
+ * p pointer to a Atm_address
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+usp_print_atm_addr(p)
+ Atm_addr *p;
+{
+ char *cp;
+
+ cp = unisig_addr_print(p);
+ printf("%s", cp);
+}
+
+
+/*
+ * Print a Q.2931 message structure
+ *
+ * Arguments:
+ * msg pointer to the message to print
+ *
+ * Returns:
+ * None
+ *
+ */
+void
+usp_print_msg(msg, dir)
+ struct unisig_msg *msg;
+ int dir;
+{
+ char *name;
+ int i;
+ struct ie_generic *ie, *inxt;
+
+ name = find_type(msg_types, msg->msg_type);
+ switch (dir) {
+ case UNISIG_MSG_IN:
+ printf("Received ");
+ break;
+ case UNISIG_MSG_OUT:
+ printf("Sent ");
+ break;
+ }
+ printf("message: %s (%x)\n", name, msg->msg_type);
+ printf(" Call reference: 0x%x\n", msg->msg_call_ref);
+#ifdef LONG_PRINT
+ printf(" Message type flag: 0x%x\n", msg->msg_type_flag);
+ printf(" Message type action: 0x%x\n", msg->msg_type_action);
+ printf(" Message length: %d\n", msg->msg_length);
+ for (i=0; i<UNI_MSG_IE_CNT; i++) {
+ ie = msg->msg_ie_vec[i];
+ while (ie) {
+ inxt = ie->ie_next;
+ usp_print_ie(ie);
+ ie = inxt;
+ }
+ }
+#else
+ for (i=0; i<UNI_MSG_IE_CNT; i++)
+ {
+ ie = msg->msg_ie_vec[i];
+ while (ie) {
+ inxt = ie->ie_next;
+ name = find_type(ie_types, ie->ie_ident);
+ if (ie->ie_ident == UNI_IE_CAUS ||
+ ie->ie_ident == UNI_IE_RSTI ||
+ ie->ie_ident == UNI_IE_CLST) {
+ usp_print_ie(ie);
+ } else {
+ printf(" Information element: %s (0x%x)\n",
+ name, ie->ie_ident);
+ }
+ ie = inxt;
+ }
+ }
+#endif
+}
+
+
+/*
+ * Print a Q.2931 information element
+ *
+ * Arguments:
+ * ie pointer to the IE to print
+ *
+ * Returns:
+ * None
+ *
+ */
+static void
+usp_print_ie(ie)
+ struct ie_generic *ie;
+{
+ char *name;
+
+ while (ie) {
+ name = find_type(ie_types, ie->ie_ident);
+ printf(" Information element: %s (0x%x)\n",
+ name, ie->ie_ident);
+#ifdef LONG_PRINT
+ printf(" Coding: 0x%x\n",
+ ie->ie_coding);
+ printf(" Flag: 0x%x\n", ie->ie_flag);
+ printf(" Action: 0x%x\n",
+ ie->ie_action);
+ printf(" Length: %d\n", ie->ie_length);
+#endif
+
+ switch (ie->ie_ident) {
+ case UNI_IE_AALP:
+ usp_print_ie_aalp(ie);
+ break;
+ case UNI_IE_CLRT:
+ usp_print_ie_clrt(ie);
+ break;
+ case UNI_IE_BBCP:
+ usp_print_ie_bbcp(ie);
+ break;
+ case UNI_IE_BHLI:
+ usp_print_ie_bhli(ie);
+ break;
+ case UNI_IE_BLLI:
+ usp_print_ie_blli(ie);
+ break;
+ case UNI_IE_CLST:
+ usp_print_ie_clst(ie);
+ break;
+ case UNI_IE_CDAD:
+ usp_print_ie_cdad(ie);
+ break;
+ case UNI_IE_CDSA:
+ usp_print_ie_cdsa(ie);
+ break;
+ case UNI_IE_CGAD:
+ usp_print_ie_cgad(ie);
+ break;
+ case UNI_IE_CGSA:
+ usp_print_ie_cgsa(ie);
+ break;
+ case UNI_IE_CAUS:
+ usp_print_ie_caus(ie);
+ break;
+ case UNI_IE_CNID:
+ usp_print_ie_cnid(ie);
+ break;
+ case UNI_IE_QOSP:
+ usp_print_ie_qosp(ie);
+ break;
+ case UNI_IE_BRPI:
+ usp_print_ie_brpi(ie);
+ break;
+ case UNI_IE_RSTI:
+ usp_print_ie_rsti(ie);
+ break;
+ case UNI_IE_BLSH:
+ usp_print_ie_blsh(ie);
+ break;
+ case UNI_IE_BNSH:
+ usp_print_ie_bnsh(ie);
+ break;
+ case UNI_IE_BSDC:
+ usp_print_ie_bsdc(ie);
+ break;
+ case UNI_IE_TRNT:
+ usp_print_ie_trnt(ie);
+ break;
+ case UNI_IE_EPRF:
+ usp_print_ie_eprf(ie);
+ break;
+ case UNI_IE_EPST:
+ usp_print_ie_epst(ie);
+ break;
+ }
+ ie = ie->ie_next;
+ }
+}
+
+
+/*
+ * Print an AAL parameters information element
+ *
+ * Arguments:
+ * ie pointer to the IE to print
+ *
+ * Returns:
+ * None
+ *
+ */
+static void
+usp_print_ie_aalp(ie)
+ struct ie_generic *ie;
+{
+ printf(" AAL type: %d\n", ie->ie_aalp_aal_type);
+ switch(ie->ie_aalp_aal_type) {
+ case UNI_IE_AALP_AT_AAL1:
+ printf(" Subtype: 0x%x\n",
+ ie->ie_aalp_1_subtype);
+ printf(" CBR rate: 0x%x\n",
+ ie->ie_aalp_1_cbr_rate);
+ printf(" Multiplier: 0x%x\n",
+ ie->ie_aalp_1_multiplier);
+ printf(" Clock rcvry: 0x%x\n",
+ ie->ie_aalp_1_clock_recovery);
+ printf(" Err corr: 0x%x\n",
+ ie->ie_aalp_1_error_correction);
+ printf(" Struct data: 0x%x\n",
+ ie->ie_aalp_1_struct_data_tran);
+ printf(" Partial cells: 0x%x\n",
+ ie->ie_aalp_1_partial_cells);
+ break;
+ case UNI_IE_AALP_AT_AAL3:
+ printf(" Fwd max SDU: %d\n",
+ ie->ie_aalp_4_fwd_max_sdu);
+ printf(" Bkwd max SDU: %d\n",
+ ie->ie_aalp_4_bkwd_max_sdu);
+ printf(" MID range: %d\n",
+ ie->ie_aalp_4_mid_range);
+ printf(" Mode: 0x%x\n",
+ ie->ie_aalp_4_mode);
+ printf(" SSCS type: 0x%x\n",
+ ie->ie_aalp_4_sscs_type);
+ break;
+ case UNI_IE_AALP_AT_AAL5:
+ printf(" Fwd max SDU: %d\n",
+ ie->ie_aalp_5_fwd_max_sdu);
+ printf(" Bkwd max SDU: %d\n",
+ ie->ie_aalp_5_bkwd_max_sdu);
+ printf(" Mode: 0x%x\n",
+ ie->ie_aalp_5_mode);
+ printf(" SSCS type: 0x%x\n",
+ ie->ie_aalp_5_sscs_type);
+ break;
+ case UNI_IE_AALP_AT_AALU:
+ printf(" User info: 0x%x %x %x %x\n",
+ ie->ie_aalp_user_info[0],
+ ie->ie_aalp_user_info[1],
+ ie->ie_aalp_user_info[2],
+ ie->ie_aalp_user_info[3]);
+ break;
+ }
+}
+
+
+/*
+ * Print a user cell rate information element
+ *
+ * Arguments:
+ * ie pointer to the IE to print
+ *
+ * Returns:
+ * None
+ *
+ */
+static void
+usp_print_ie_clrt(ie)
+ struct ie_generic *ie;
+{
+ printf(" Forward peak: %d\n", ie->ie_clrt_fwd_peak);
+ printf(" Backward peak: %d\n", ie->ie_clrt_bkwd_peak);
+ printf(" Fwd peak 01: %d\n", ie->ie_clrt_fwd_peak_01);
+ printf(" Bkwd peak 01: %d\n", ie->ie_clrt_bkwd_peak_01);
+ printf(" Fwd sust: %d\n", ie->ie_clrt_fwd_sust);
+ printf(" Bkwd sust: %d\n", ie->ie_clrt_bkwd_sust);
+ printf(" Fwd sust 01: %d\n", ie->ie_clrt_fwd_sust_01);
+ printf(" Bkwd sust 01: %d\n", ie->ie_clrt_bkwd_sust_01);
+ printf(" Fwd burst: %d\n", ie->ie_clrt_fwd_burst);
+ printf(" Bkwd burst: %d\n", ie->ie_clrt_bkwd_burst);
+ printf(" Fwd burst 01: %d\n", ie->ie_clrt_fwd_burst_01);
+ printf(" Bkwd burst 01: %d\n",
+ ie->ie_clrt_bkwd_burst_01);
+ printf(" Best effort: %d\n", ie->ie_clrt_best_effort);
+ printf(" TM optons: 0x%x\n",
+ ie->ie_clrt_tm_options);
+}
+
+
+/*
+ * Print a broadband bearer capability information element
+ *
+ * Arguments:
+ * ie pointer to the IE to print
+ *
+ * Returns:
+ * None
+ *
+ */
+static void
+usp_print_ie_bbcp(ie)
+ struct ie_generic *ie;
+{
+ printf(" Bearer class: 0x%x\n",
+ ie->ie_bbcp_bearer_class);
+ printf(" Traffic type: 0x%x\n",
+ ie->ie_bbcp_traffic_type);
+ printf(" Timing req: 0x%x\n",
+ ie->ie_bbcp_timing_req);
+ printf(" Clipping: 0x%x\n", ie->ie_bbcp_clipping);
+ printf(" Conn config: 0x%x\n",
+ ie->ie_bbcp_conn_config);
+}
+
+
+/*
+ * Print a broadband high layer information information element
+ *
+ * Arguments:
+ * ie pointer to the IE to print
+ *
+ * Returns:
+ * None
+ *
+ */
+static void
+usp_print_ie_bhli(ie)
+ struct ie_generic *ie;
+{
+ int i;
+
+ printf(" Type: 0x%x\n", ie->ie_bhli_type);
+ printf(" HL info: 0x");
+ for (i=0; i<ie->ie_length-1; i++) {
+ printf("%x ", ie->ie_bhli_info[i]);
+ }
+ printf("\n");
+}
+
+
+/*
+ * Print a broadband low-layer information information element
+ *
+ * Arguments:
+ * ie pointer to the IE to print
+ *
+ * Returns:
+ * None
+ *
+ */
+static void
+usp_print_ie_blli(ie)
+ struct ie_generic *ie;
+{
+ printf(" Layer 1 ID: 0x%x\n", ie->ie_blli_l1_id);
+ printf(" Layer 2 ID: 0x%x\n", ie->ie_blli_l2_id);
+ printf(" Layer 2 mode: 0x%x\n", ie->ie_blli_l2_mode);
+ printf(" Layer 2 Q.933: 0x%x\n",
+ ie->ie_blli_l2_q933_use);
+ printf(" Layer 2 win: 0x%x\n",
+ ie->ie_blli_l2_window);
+ printf(" Layer 2 user: 0x%x\n",
+ ie->ie_blli_l2_user_proto);
+ printf(" Layer 3 ID: 0x%x\n", ie->ie_blli_l3_id);
+ printf(" Layer 3 mode: 0x%x\n", ie->ie_blli_l3_mode);
+ printf(" Layer 3 pkt: 0x%x\n",
+ ie->ie_blli_l3_packet_size);
+ printf(" Layer 3 win: 0x%x\n",
+ ie->ie_blli_l3_window);
+ printf(" Layer 3 user: 0x%x\n",
+ ie->ie_blli_l3_user_proto);
+ printf(" Layer 3 IPI: 0x%x\n", ie->ie_blli_l3_ipi);
+ printf(" Layer 3 SNAP: 0x%x\n",
+ ie->ie_blli_l3_snap_id);
+ printf(" Layer 3 OUI: 0x%x %x %x\n",
+ ie->ie_blli_l3_oui[0],
+ ie->ie_blli_l3_oui[1],
+ ie->ie_blli_l3_oui[2]);
+ printf(" Layer 3 PID: 0x%x %x\n",
+ ie->ie_blli_l3_pid[0],
+ ie->ie_blli_l3_pid[1]);
+}
+
+
+/*
+ * Print a call state information element
+ *
+ * Arguments:
+ * ie pointer to the IE to print
+ *
+ * Returns:
+ * None
+ *
+ */
+static void
+usp_print_ie_clst(ie)
+ struct ie_generic *ie;
+{
+ printf(" Call state: %d\n",
+ ie->ie_clst_state);
+}
+
+
+/*
+ * Print a called party number information element
+ *
+ * Arguments:
+ * ie pointer to the IE to print
+ *
+ * Returns:
+ * None
+ *
+ */
+static void
+usp_print_ie_cdad(ie)
+ struct ie_generic *ie;
+{
+ printf(" ATM addr: ");
+ usp_print_atm_addr(&ie->ie_cdad_addr);
+ printf("\n");
+}
+
+
+/*
+ * Print a called party subaddress information element
+ *
+ * Arguments:
+ * ie pointer to the IE to print
+ *
+ * Returns:
+ * None
+ *
+ */
+static void
+usp_print_ie_cdsa(ie)
+ struct ie_generic *ie;
+{
+ printf(" ATM subaddr: ");
+ usp_print_atm_addr(&ie->ie_cdsa_addr);
+ printf("\n");
+}
+
+
+/*
+ * Print a calling party number information element
+ *
+ * Arguments:
+ * ie pointer to the IE to print
+ *
+ * Returns:
+ * None
+ *
+ */
+static void
+usp_print_ie_cgad(ie)
+ struct ie_generic *ie;
+{
+ printf(" ATM addr: ");
+ usp_print_atm_addr(&ie->ie_cgad_addr);
+ printf("\n");
+}
+
+
+/*
+ * Print a calling party subaddress information element
+ *
+ * Arguments:
+ * ie pointer to the IE to print
+ *
+ * Returns:
+ * None
+ *
+ */
+static void
+usp_print_ie_cgsa(ie)
+ struct ie_generic *ie;
+{
+ printf(" ATM subaddr: ");
+ usp_print_atm_addr(&ie->ie_cgsa_addr);
+ printf("\n");
+}
+
+
+/*
+ * Print a cause information element
+ *
+ * Arguments:
+ * ie pointer to the IE to print
+ *
+ * Returns:
+ * None
+ *
+ */
+static void
+usp_print_ie_caus(ie)
+ struct ie_generic *ie;
+{
+ int i;
+
+ printf(" Location: %d\n", ie->ie_caus_loc);
+ printf(" Cause: %d\n", ie->ie_caus_cause);
+ switch(ie->ie_caus_cause) {
+ case UNI_IE_CAUS_IECONTENT:
+ printf(" Flagged IEs: ");
+ for (i=0; ie->ie_caus_diagnostic[i]; i++) {
+ printf("0x%x ", ie->ie_caus_diagnostic[i]);
+ }
+ printf("\n");
+ break;
+ case UNI_IE_CAUS_TIMER:
+ printf(" Timer ID: %c%c%c\n",
+ ie->ie_caus_diagnostic[0],
+ ie->ie_caus_diagnostic[1],
+ ie->ie_caus_diagnostic[2]);
+ break;
+ default:
+ printf(" Diag length: %d\n",
+ ie->ie_caus_diag_len);
+ printf(" Diagnostic: ");
+ for (i=0; i<ie->ie_caus_diag_len; i++) {
+ printf("0x%x ", ie->ie_caus_diagnostic[i]);
+ }
+ printf("\n");
+ }
+}
+
+
+/*
+ * Print a connection identifier information element
+ *
+ * Arguments:
+ * ie pointer to the IE to print
+ *
+ * Returns:
+ * None
+ *
+ */
+static void
+usp_print_ie_cnid(ie)
+ struct ie_generic *ie;
+{
+ printf(" VP assoc sig: 0x%x\n", ie->ie_cnid_vp_sig);
+ printf(" Pref/excl: 0x%x\n",
+ ie->ie_cnid_pref_excl);
+ printf(" VPCI: %d\n", ie->ie_cnid_vpci);
+ printf(" VCI: %d\n", ie->ie_cnid_vci);
+}
+
+
+/*
+ * Print a quality of service parameter information element
+ *
+ * Arguments:
+ * ie pointer to the IE to print
+ *
+ * Returns:
+ * None
+ *
+ */
+static void
+usp_print_ie_qosp(ie)
+ struct ie_generic *ie;
+{
+ printf(" QoS fwd: 0x%x\n",
+ ie->ie_qosp_fwd_class);
+ printf(" QoS bkwd: 0x%x\n",
+ ie->ie_qosp_bkwd_class);
+}
+
+
+/*
+ * Print a broadband repeat indicator information element
+ *
+ * Arguments:
+ * ie pointer to the IE to print
+ *
+ * Returns:
+ * None
+ *
+ */
+static void
+usp_print_ie_brpi(ie)
+ struct ie_generic *ie;
+{
+ printf(" Indicator: 0x%x\n", ie->ie_brpi_ind);
+}
+
+
+/*
+ * Print a restart indicator information element
+ *
+ * Arguments:
+ * ie pointer to the IE to print
+ *
+ * Returns:
+ * None
+ *
+ */
+static void
+usp_print_ie_rsti(ie)
+ struct ie_generic *ie;
+{
+ printf(" Class: 0x%x\n", ie->ie_rsti_class);
+}
+
+
+/*
+ * Print a broadband locking shift information element
+ *
+ * Arguments:
+ * ie pointer to the IE to print
+ *
+ * Returns:
+ * None
+ *
+ */
+static void
+usp_print_ie_blsh(ie)
+ struct ie_generic *ie;
+{
+}
+
+
+/*
+ * Print a broadband non-locking shift information element
+ *
+ * Arguments:
+ * ie pointer to the IE to print
+ *
+ * Returns:
+ * None
+ *
+ */
+static void
+usp_print_ie_bnsh(ie)
+ struct ie_generic *ie;
+{
+}
+
+
+/*
+ * Print a broadband sending complete information element
+ *
+ * Arguments:
+ * ie pointer to the IE to print
+ *
+ * Returns:
+ * None
+ *
+ */
+static void
+usp_print_ie_bsdc(ie)
+ struct ie_generic *ie;
+{
+ printf(" Indication: 0x%x\n", ie->ie_bsdc_ind);
+}
+
+
+/*
+ * Print a transit net selection information element
+ *
+ * Arguments:
+ * ie pointer to the IE to print
+ *
+ * Returns:
+ * None
+ *
+ */
+static void
+usp_print_ie_trnt(ie)
+ struct ie_generic *ie;
+{
+#ifdef NOTDEF
+ struct ie_generic ie_trnt_hdr;
+ u_char ie_trnt_id_type;
+ u_char ie_trnt_id_plan;
+ Atm_addr ie_trnt_id;
+#endif
+}
+
+
+/*
+ * Print an endpoint reference information element
+ *
+ * Arguments:
+ * ie pointer to the IE to print
+ *
+ * Returns:
+ * None
+ *
+ */
+static void
+usp_print_ie_eprf(ie)
+ struct ie_generic *ie;
+{
+ printf(" Ref type: 0x%x\n",
+ ie->ie_eprf_type);
+ printf(" Endpt ref: 0x%x\n",
+ ie->ie_eprf_id);
+}
+
+
+/*
+ * Print an endpoint state information element
+ *
+ * Arguments:
+ * ie pointer to the IE to print
+ *
+ * Returns:
+ * None
+ *
+ */
+static void
+usp_print_ie_epst(ie)
+ struct ie_generic *ie;
+{
+ printf(" Endpt state: %d\n",
+ ie->ie_epst_state);
+}
diff --git a/sys/netatm/uni/unisig_print.h b/sys/netatm/uni/unisig_print.h
new file mode 100644
index 0000000..5e906c8
--- /dev/null
+++ b/sys/netatm/uni/unisig_print.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * ===================================
+ * 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: unisig_print.h,v 1.2 1997/05/06 22:22:27 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI 3.0/3.1 Signalling Manager
+ * ----------------------------------------
+ *
+ * Protocol control blocks
+ *
+ */
+
+#ifndef _UNISIG_PRINT_H
+#define _UNISIG_PRINT_H
+
+/*
+ * Message direction for print routine
+ */
+#define UNISIG_MSG_IN 1
+#define UNISIG_MSG_OUT 2
+
+#endif /* _UNISIG_PRINT_H */
diff --git a/sys/netatm/uni/unisig_proto.c b/sys/netatm/uni/unisig_proto.c
new file mode 100644
index 0000000..914e76d
--- /dev/null
+++ b/sys/netatm/uni/unisig_proto.c
@@ -0,0 +1,324 @@
+/*
+ *
+ * ===================================
+ * 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: unisig_proto.c,v 1.9 1998/08/26 23:29:23 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI 3.0/3.1 Signalling Manager
+ * ----------------------------------------
+ *
+ * Protocol processing module.
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: unisig_proto.c,v 1.9 1998/08/26 23:29:23 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/unisig.h>
+#include <netatm/uni/unisig_var.h>
+#include <netatm/uni/unisig_msg.h>
+#include <netatm/uni/unisig_mbuf.h>
+
+
+/*
+ * Process a UNISIG timeout
+ *
+ * Called when a previously scheduled protocol instance control block
+ * timer expires. This routine passes a timeout event to the UNISIG
+ * signalling manager state machine.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * tip pointer to UNISIG timer control block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+unisig_timer(tip)
+ struct atm_time *tip;
+{
+ struct unisig *usp;
+
+ /*
+ * Back-off to UNISIG control block
+ */
+ usp = (struct unisig *)
+ ((caddr_t)tip - (int)(&((struct unisig *)0)->us_time));
+
+ ATM_DEBUG2("unisig_timer: usp=0x%x,state=%d\n",
+ (int)usp, usp->us_state);
+
+ /*
+ * Pass the timeout to the signalling manager state machine
+ */
+ (void) unisig_sigmgr_state(usp,
+ UNISIG_SIGMGR_TIMEOUT,
+ (KBuffer *) 0);
+}
+
+
+/*
+ * Process a UNISIG VCC timeout
+ *
+ * Called when a previously scheduled UNISIG 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
+unisig_vctimer(tip)
+ struct atm_time *tip;
+{
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+
+ /*
+ * Get VCCB and UNISIG control block addresses
+ */
+ uvp = (struct unisig_vccb *) ((caddr_t)tip -
+ (int)(&((struct vccb *)0)->vc_time));
+ usp = (struct unisig *)uvp->uv_pif->pif_siginst;
+
+ ATM_DEBUG3("unisig_vctimer: uvp=0x%x, sstate=%d, ustate=%d\n",
+ (int)uvp, uvp->uv_sstate, uvp->uv_ustate);
+
+ /*
+ * Hand the timeout to the VC finite state machine
+ */
+ if (uvp->uv_ustate == VCCU_ABORT) {
+ /*
+ * If we're aborting, this is an ABORT call
+ */
+ (void) unisig_vc_state(usp, uvp, UNI_VC_ABORT_CALL,
+ (struct unisig_msg *) 0);
+ } else {
+ /*
+ * If we're not aborting, it's a timeout
+ */
+ (void) unisig_vc_state(usp, uvp, UNI_VC_TIMEOUT,
+ (struct unisig_msg *) 0);
+ }
+}
+
+
+/*
+ * UNISIG SAAL Control Handler
+ *
+ * This is the module which receives data on the UNISIG signalling
+ * channel. Processing is based on the indication received from the
+ * SSCF and the protocol state.
+ *
+ * Arguments:
+ * cmd command code
+ * tok session token (pointer to UNISIG protocol control block)
+ * a1 argument 1
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+unisig_saal_ctl(cmd, tok, a1)
+ int cmd;
+ void *tok;
+ void *a1;
+{
+ struct unisig *usp = tok;
+
+ ATM_DEBUG4("unisig_upper: usp=0x%x,state=%d,cmd=%d,a1=0x%x,\n",
+ (u_long)usp, usp->us_state, cmd, (u_long)a1);
+
+ /*
+ * Process command
+ */
+ switch (cmd) {
+
+ case SSCF_UNI_ESTABLISH_IND:
+ (void) unisig_sigmgr_state(usp,
+ UNISIG_SIGMGR_SSCF_EST_IND,
+ (KBuffer *) 0);
+ break;
+
+ case SSCF_UNI_ESTABLISH_CNF:
+ (void) unisig_sigmgr_state(usp,
+ UNISIG_SIGMGR_SSCF_EST_CNF,
+ (KBuffer *) 0);
+ break;
+
+ case SSCF_UNI_RELEASE_IND:
+ (void) unisig_sigmgr_state(usp,
+ UNISIG_SIGMGR_SSCF_RLS_IND,
+ (KBuffer *) 0);
+ break;
+
+ case SSCF_UNI_RELEASE_CNF:
+ (void) unisig_sigmgr_state(usp,
+ UNISIG_SIGMGR_SSCF_RLS_CNF,
+ (KBuffer *) 0);
+ break;
+
+ default:
+ log(LOG_ERR,
+ "unisig: unknown SAAL cmd: usp=0x%x, state=%d, cmd=%d\n",
+ (int)usp, usp->us_state, cmd);
+ }
+}
+
+
+/*
+ * UNISIG SAAL Data Handler
+ *
+ * This is the module which receives data on the UNISIG signalling
+ * channel. Processing is based on the protocol state.
+ *
+ * Arguments:
+ * tok session token (pointer to UNISIG protocol control block)
+ * m pointer to data
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+unisig_saal_data(tok, m)
+ void *tok;
+ KBuffer *m;
+{
+ struct unisig *usp = tok;
+
+ ATM_DEBUG3("unisig_saal_data: usp=0x%x,state=%d,m=0x%x,\n",
+ (int)usp, usp->us_state, m);
+
+ /*
+ * Pass data to signalling manager state machine
+ */
+ (void) unisig_sigmgr_state(usp,
+ UNISIG_SIGMGR_SSCF_DATA_IND,
+ m);
+}
+
+
+/*
+ * Get Connection's Application/Owner Name
+ *
+ * Arguments:
+ * tok UNI signalling connection token (pointer to protocol instance)
+ *
+ * Returns:
+ * addr pointer to string containing our name
+ *
+ */
+caddr_t
+unisig_getname(tok)
+ void *tok;
+{
+ struct unisig *usp = tok;
+
+ if (usp->us_proto == ATM_SIG_UNI30)
+ return ("UNI3.0");
+ else if (usp->us_proto == ATM_SIG_UNI31)
+ return ("UNI3.1");
+ else if (usp->us_proto == ATM_SIG_UNI40)
+ return ("UNI4.0");
+ else
+ return ("UNI");
+}
+
+
+/*
+ * Process a VCC connection notification
+ *
+ * Should never be called.
+ *
+ * Arguments:
+ * tok user's connection token (unisig protocol block)
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+unisig_connected(tok)
+ void *tok;
+{
+ struct unisig *usp = tok;
+
+ ATM_DEBUG2("unisig_connected: usp=0x%x,state=%d\n",
+ (u_long)usp, usp->us_state);
+
+ /*
+ * Connected routine shouldn't ever get called for a PVC
+ */
+ log(LOG_ERR, "unisig: connected notification, usp=0x%x\n",
+ (u_long)usp);
+}
+
+
+/*
+ * Process a VCC closed notification
+ *
+ * Called when UNISIG signalling channel is closed.
+ *
+ * Arguments:
+ * tok user's connection token (unisig protocol block)
+ * cp pointer to cause structure
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+unisig_cleared(tok, cp)
+ void *tok;
+ struct t_atm_cause *cp;
+{
+ struct unisig *usp = tok;
+
+ ATM_DEBUG3("unisig_cleared: usp=0x%x, state=%d, cause=%d\n",
+ (u_long)usp, usp->us_state, cp->cause_value);
+
+ /*
+ * VCC has been closed. Notify the signalling
+ * manager state machine.
+ */
+ (void) unisig_sigmgr_state(usp,
+ UNISIG_SIGMGR_CALL_CLEARED,
+ (KBuffer *) 0);
+}
diff --git a/sys/netatm/uni/unisig_sigmgr_state.c b/sys/netatm/uni/unisig_sigmgr_state.c
new file mode 100644
index 0000000..2fbbfca
--- /dev/null
+++ b/sys/netatm/uni/unisig_sigmgr_state.c
@@ -0,0 +1,860 @@
+/*
+ *
+ * ===================================
+ * 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: unisig_sigmgr_state.c,v 1.10 1998/08/26 23:29:24 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI 3.0/3.1 Signalling Manager
+ * ----------------------------------------
+ *
+ * Signalling manager finite state machine
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: unisig_sigmgr_state.c,v 1.10 1998/08/26 23:29:24 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/uni.h>
+#include <netatm/uni/unisig.h>
+#include <netatm/uni/unisig_var.h>
+#include <netatm/uni/unisig_msg.h>
+#include <netatm/uni/unisig_mbuf.h>
+#include <netatm/uni/unisig_decode.h>
+
+#include <netatm/uni/sscf_uni.h>
+
+
+/*
+ * Local functions
+ */
+static int unisig_sigmgr_invalid __P((struct unisig *, KBuffer *));
+static int unisig_sigmgr_act01 __P((struct unisig *, KBuffer *));
+static int unisig_sigmgr_act02 __P((struct unisig *, KBuffer *));
+static int unisig_sigmgr_act03 __P((struct unisig *, KBuffer *));
+static int unisig_sigmgr_act04 __P((struct unisig *, KBuffer *));
+static int unisig_sigmgr_act05 __P((struct unisig *, KBuffer *));
+static int unisig_sigmgr_act06 __P((struct unisig *, KBuffer *));
+static int unisig_sigmgr_act07 __P((struct unisig *, KBuffer *));
+static int unisig_sigmgr_act08 __P((struct unisig *, KBuffer *));
+static int unisig_sigmgr_act09 __P((struct unisig *, KBuffer *));
+static int unisig_sigmgr_act10 __P((struct unisig *, KBuffer *));
+static int unisig_sigmgr_act11 __P((struct unisig *, KBuffer *));
+static int unisig_sigmgr_act12 __P((struct unisig *, KBuffer *));
+static int unisig_sigmgr_act13 __P((struct unisig *, KBuffer *));
+static int unisig_sigmgr_act14 __P((struct unisig *, KBuffer *));
+
+
+/*
+ * State table.
+ */
+static int sigmgr_state_table[10][7] = {
+ /* 0 1 2 3 4 5 */
+ { 1, 0, 0, 0, 0 }, /* 0 - Time out */
+ { 0, 0, 3, 5, 0 }, /* 1 - SSCF estab ind */
+ { 0, 0, 3, 5, 0 }, /* 2 - SSCF estab cnf */
+ { 0, 0, 4, 6, 0 }, /* 3 - SSCF release ind */
+ { 0, 0, 0, 6, 0 }, /* 4 - SSCF release cnf */
+ { 0, 0, 0, 7, 0 }, /* 5 - SSCF data ind */
+ { 0, 0, 2, 2, 0 }, /* 6 - SSCF unit data ind */
+ { 0, 0, 8, 8, 8 }, /* 7 - Call cleared */
+ { 14, 14, 14, 14, 0 }, /* 8 - Detach */
+ { 13, 13, 0, 0, 0 } /* 9 - Address set */
+};
+
+/*
+ * Action vector
+ */
+#define MAX_ACTION 15
+static int (*unisig_sigmgr_act_vec[MAX_ACTION])
+ __P((struct unisig *, KBuffer *)) = {
+ unisig_sigmgr_invalid,
+ unisig_sigmgr_act01,
+ unisig_sigmgr_act02,
+ unisig_sigmgr_act03,
+ unisig_sigmgr_act04,
+ unisig_sigmgr_act05,
+ unisig_sigmgr_act06,
+ unisig_sigmgr_act07,
+ unisig_sigmgr_act08,
+ unisig_sigmgr_act09,
+ unisig_sigmgr_act10,
+ unisig_sigmgr_act11,
+ unisig_sigmgr_act12,
+ unisig_sigmgr_act13,
+ unisig_sigmgr_act14
+};
+
+
+/*
+ * ATM endpoint for UNI signalling channel
+ */
+static Atm_endpoint unisig_endpt = {
+ NULL, /* ep_next */
+ ENDPT_UNI_SIG, /* ep_id */
+ NULL, /* ep_ioctl */
+ unisig_getname, /* ep_getname */
+ unisig_connected, /* ep_connected */
+ unisig_cleared, /* ep_cleared */
+ NULL, /* ep_incoming */
+ NULL, /* ep_addparty */
+ NULL, /* ep_dropparty */
+ NULL, /* ep_cpcs_ctl */
+ NULL, /* ep_cpcs_data */
+ unisig_saal_ctl, /* ep_saal_ctl */
+ unisig_saal_data, /* ep_saal_data */
+ NULL, /* ep_sscop_ctl */
+ NULL /* ep_sscop_data */
+};
+
+
+/*
+ * ATM connection attributes for UNI signalling channel
+ */
+static Atm_attributes unisig_attr = {
+ NULL, /* nif */
+ CMAPI_SAAL, /* api */
+ UNI_VERS_3_0, /* api_init */
+ 0, /* headin */
+ 0, /* headout */
+ { /* aal */
+ T_ATM_PRESENT, /* aal.tag */
+ ATM_AAL5 /* 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 */
+ }
+};
+
+
+/*
+ * Finite state machine for the UNISIG signalling manager
+ *
+ * Arguments:
+ * usp pointer to the UNISIG protocol control block
+ * event indication of the event to be processed
+ * m pointer to a buffer with a message (optional)
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+unisig_sigmgr_state(usp, event, m)
+ struct unisig *usp;
+ int event;
+ KBuffer *m;
+{
+ int action, err = 0;
+
+ /*
+ * Cancel any signalling manager timer
+ */
+ UNISIG_CANCEL(usp);
+
+ /*
+ * Select an action based on the incoming event and
+ * the signalling manager's state
+ */
+ action = sigmgr_state_table[event][usp->us_state];
+ ATM_DEBUG4("unisig_sigmgr_state: usp=0x%x, state=%d, event=%d, action=%d\n",
+ (u_int) usp, usp->us_state, event, action);
+ if (action >= MAX_ACTION || action < 0) {
+ panic("unisig_sigmgr_state: invalid action\n");
+ }
+
+ /*
+ * Perform the requested action
+ */
+ err = unisig_sigmgr_act_vec[action](usp, m);
+
+ return(err);
+}
+
+
+/*
+ * Signalling manager state machine action 0
+ *
+ * Invalid action
+ *
+ * Arguments:
+ * usp pointer to the UNISIG protocol control block
+ * m buffer pointer (may be NULL)
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_sigmgr_invalid(usp, m)
+ struct unisig *usp;
+ KBuffer *m;
+{
+ log(LOG_ERR, "unisig_sigmgr_state: unexpected action\n");
+ if (m)
+ KB_FREEALL(m);
+ return(0);
+}
+
+
+/*
+ * Signalling manager state machine action 1
+ *
+ * The kickoff timer has expired at attach time; go to
+ * UNISIG_ADDR_WAIT state.
+ *
+ * Arguments:
+ * usp pointer to the UNISIG protocol control block
+ * m buffer pointer (may be NULL)
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_sigmgr_act01(usp, m)
+ struct unisig *usp;
+ KBuffer *m;
+{
+ /*
+ * Set the new state
+ */
+ usp->us_state = UNISIG_ADDR_WAIT;
+
+ return(0);
+}
+
+
+/*
+ * Signalling manager state machine action 2
+ *
+ * Ignore the event
+ *
+ * Arguments:
+ * usp pointer to the UNISIG protocol control block
+ * m buffer pointer (may be NULL)
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_sigmgr_act02(usp, m)
+ struct unisig *usp;
+ KBuffer *m;
+{
+ /*
+ * Ignore event, discard message if present
+ */
+ if (m)
+ KB_FREEALL(m);
+
+ return(0);
+}
+
+
+/*
+ * Signalling manager state machine action 3
+ *
+ * SSCF session on signalling channel has come up
+ *
+ * Arguments:
+ * usp pointer to the UNISIG protocol control block
+ * m buffer pointer (may be NULL)
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_sigmgr_act03(usp, m)
+ struct unisig *usp;
+ KBuffer *m;
+{
+ struct unisig_vccb *uvp, *vnext;
+
+ /*
+ * Log the activation
+ */
+ log(LOG_INFO, "unisig: signalling channel active\n");
+
+ /*
+ * Go to ACTIVE state
+ */
+ usp->us_state = UNISIG_ACTIVE;
+
+ /*
+ * Notify the VC state machine that the channel is up
+ */
+ for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb);
+ uvp; uvp = vnext) {
+ vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem);
+ (void) unisig_vc_state(usp, uvp, UNI_VC_SAAL_ESTAB,
+ (struct unisig_msg *) 0);
+ }
+
+ return(0);
+}
+
+
+/*
+ * Signalling manager state machine action 4
+ *
+ * A SSCF release indication was received. Try to establish an
+ * SSCF session on the signalling PVC.
+ *
+ * Arguments:
+ * usp pointer to the UNISIG protocol control block
+ * m buffer pointer (may be NULL)
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_sigmgr_act04(usp, m)
+ struct unisig *usp;
+ KBuffer *m;
+{
+ int err;
+
+ /*
+ * Try to establish an SSCF session.
+ */
+ err = atm_cm_saal_ctl(SSCF_UNI_ESTABLISH_REQ,
+ usp->us_conn,
+ (void *)0);
+ if (err)
+ panic("unisig_sigmgr_act04: SSCF_UNI_ESTABLISH_REQ");
+
+ return(0);
+}
+
+
+/*
+ * Signalling manager state machine action 5
+ *
+ * SSCF session on signalling channel has been reset
+ *
+ * Arguments:
+ * usp pointer to the UNISIG protocol control block
+ * m buffer pointer (may be NULL)
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_sigmgr_act05(usp, m)
+ struct unisig *usp;
+ KBuffer *m;
+{
+ struct unisig_vccb *uvp, *vnext;
+
+ /*
+ * Log the reset
+ */
+ log(LOG_INFO, "unisig: signalling channel reset\n");
+
+ /*
+ * Notify the VC state machine of the reset
+ */
+ for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb);
+ uvp; uvp = vnext) {
+ vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem);
+ (void) unisig_vc_state(usp, uvp, UNI_VC_SAAL_ESTAB,
+ (struct unisig_msg *) 0);
+ }
+
+ return(0);
+}
+
+
+/*
+ * Signalling manager state machine action 6
+ *
+ * SSCF session on signalling channel has been lost
+ *
+ * Arguments:
+ * usp pointer to the UNISIG protocol control block
+ * m buffer pointer (may be NULL)
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_sigmgr_act06(usp, m)
+ struct unisig *usp;
+ KBuffer *m;
+{
+ struct unisig_vccb *uvp, *vnext;
+
+ /*
+ * Log the fact that the session has been lost
+ */
+ log(LOG_INFO, "unisig: signalling channel SSCF session lost\n");
+
+ /*
+ * Notify the VC state machine of the loss
+ */
+ for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb);
+ uvp; uvp = vnext) {
+ vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem);
+ (void) unisig_vc_state(usp, uvp, UNI_VC_SAAL_FAIL,
+ (struct unisig_msg *) 0);
+ }
+
+ /*
+ * Try to restart the SSCF session
+ */
+ (void) unisig_sigmgr_act04(usp, (KBuffer *) 0);
+
+ /*
+ * Go to INIT state
+ */
+ usp->us_state = UNISIG_INIT;
+
+ return(0);
+}
+
+
+/*
+ * Signalling manager state machine action 7
+ *
+ * A Q.2931 signalling message has been received
+ *
+ * Arguments:
+ * usp pointer to the UNISIG protocol control block
+ * m buffer pointer (may be NULL)
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_sigmgr_act07(usp, m)
+ struct unisig *usp;
+ KBuffer *m;
+{
+ int err;
+
+ /*
+ * Pass the Q.2931 signalling message on
+ * to the VC state machine
+ */
+ err = unisig_rcv_msg(usp, m);
+
+ return(err);
+}
+
+
+/*
+ * Signalling manager state machine action 8
+ *
+ * Process a CALL_CLOSED event for the signalling PVC
+ *
+ * Arguments:
+ * usp pointer to the UNISIG protocol control block
+ * m buffer pointer (may be NULL)
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_sigmgr_act08(usp, m)
+ struct unisig *usp;
+ KBuffer *m;
+{
+
+ /*
+ * Signalling manager is now incommunicado
+ */
+ if (usp->us_state != UNISIG_DETACH) {
+ /*
+ * Log an error and set the state to NULL if
+ * we're not detaching
+ */
+ log(LOG_ERR, "unisig: signalling channel closed\n");
+ usp->us_state = UNISIG_NULL;
+ }
+ usp->us_conn = 0;
+
+ return(0);
+}
+
+
+/*
+ * Signalling manager state machine action 9
+ *
+ * Not used
+ *
+ * Arguments:
+ * usp pointer to the UNISIG protocol control block
+ * m buffer pointer (may be NULL)
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_sigmgr_act09(usp, m)
+ struct unisig *usp;
+ KBuffer *m;
+{
+ log(LOG_ERR, "unisig_sigmgr_act09: unexpected action\n");
+ if (m)
+ KB_FREEALL(m);
+ return (0);
+}
+
+
+/*
+ * Signalling manager state machine action 10
+ *
+ * Not used
+ *
+ * Arguments:
+ * usp pointer to the UNISIG protocol control block
+ * m buffer pointer (may be NULL)
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_sigmgr_act10(usp, m)
+ struct unisig *usp;
+ KBuffer *m;
+{
+ return(0);
+}
+
+
+/*
+ * Signalling manager state machine action 11
+ *
+ * Not used
+ *
+ * Arguments:
+ * usp pointer to the UNISIG protocol control block
+ * m buffer pointer (may be NULL)
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_sigmgr_act11(usp, m)
+ struct unisig *usp;
+ KBuffer *m;
+{
+ log(LOG_ERR, "unisig_sigmgr_act11: unexpected action\n");
+ if (m)
+ KB_FREEALL(m);
+ return(0);
+}
+
+
+/*
+ * Signalling manager state machine action 12
+ *
+ * Not used
+ *
+ * Arguments:
+ * usp pointer to the UNISIG protocol control block
+ * m buffer pointer (may be NULL)
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_sigmgr_act12(usp, m)
+ struct unisig *usp;
+ KBuffer *m;
+{
+ log(LOG_ERR, "unisig_sigmgr_act11: unexpected action\n");
+ if (m)
+ KB_FREEALL(m);
+ return(0);
+}
+
+
+/*
+ * Signalling manager state machine action 13
+ *
+ * NSAP prefix has been set
+ *
+ * Arguments:
+ * usp pointer to the UNISIG protocol control block
+ * m buffer pointer (may be NULL)
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_sigmgr_act13(usp, m)
+ struct unisig *usp;
+ KBuffer *m;
+{
+ int err;
+ Atm_addr_pvc *pvcp;
+
+ /*
+ * Set UNI signalling channel connection attributes
+ */
+ if (usp->us_proto == ATM_SIG_UNI30)
+ unisig_attr.api_init = UNI_VERS_3_0;
+ else
+ unisig_attr.api_init = UNI_VERS_3_1;
+
+ unisig_attr.nif = usp->us_pif->pif_nif;
+
+ unisig_attr.aal.v.aal5.forward_max_SDU_size = ATM_NIF_MTU;
+ unisig_attr.aal.v.aal5.backward_max_SDU_size = ATM_NIF_MTU;
+ unisig_attr.aal.v.aal5.SSCS_type = T_ATM_SSCS_SSCOP_REL;
+
+ unisig_attr.called.tag = T_ATM_PRESENT;
+ unisig_attr.called.addr.address_format = T_ATM_PVC_ADDR;
+ unisig_attr.called.addr.address_length = sizeof(Atm_addr_pvc);
+ pvcp = (Atm_addr_pvc *)unisig_attr.called.addr.address;
+ ATM_PVC_SET_VPI(pvcp, UNISIG_SIG_VPI);
+ ATM_PVC_SET_VCI(pvcp, UNISIG_SIG_VCI);
+ unisig_attr.called.subaddr.address_format = T_ATM_ABSENT;
+ unisig_attr.called.subaddr.address_length = 0;
+
+ unisig_attr.traffic.v.forward.PCR_all_traffic =
+ usp->us_pif->pif_pcr;
+ unisig_attr.traffic.v.backward.PCR_all_traffic =
+ usp->us_pif->pif_pcr;
+
+ /*
+ * Create UNISIG signalling channel
+ */
+ err = atm_cm_connect(&unisig_endpt, usp, &unisig_attr,
+ &usp->us_conn);
+ if (err) {
+ return(err);
+ }
+
+ /*
+ * Establish the SSCF session
+ */
+ err = atm_cm_saal_ctl(SSCF_UNI_ESTABLISH_REQ,
+ usp->us_conn,
+ (void *)0);
+ if (err)
+ panic("unisig_sigmgr_act13: SSCF_UNI_ESTABLISH_REQ");
+
+ /*
+ * Set the new state
+ */
+ usp->us_state = UNISIG_INIT;
+
+ return(0);
+}
+
+
+/*
+ * Signalling manager state machine action 14
+ *
+ * Process a detach event
+ *
+ * Arguments:
+ * usp pointer to the UNISIG protocol control block
+ * m buffer pointer (may be NULL)
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_sigmgr_act14(usp, m)
+ struct unisig *usp;
+ KBuffer *m;
+{
+ int err;
+ struct unisig_vccb *sig_vccb, *uvp, *vnext;
+ struct atm_pif *pip;
+ struct t_atm_cause cause;
+
+ /*
+ * Locate the signalling channel's VCCB
+ */
+ sig_vccb = (struct unisig_vccb *)0;
+ if (usp->us_conn && usp->us_conn->co_connvc)
+ sig_vccb = (struct unisig_vccb *)
+ usp->us_conn->co_connvc->cvc_vcc;
+
+ /*
+ * Terminate all of our VCCs
+ */
+ for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb);
+ uvp; uvp = vnext) {
+ vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem);
+
+ /*
+ * Don't close the signalling VCC yet
+ */
+ if (uvp == sig_vccb)
+ continue;
+
+ /*
+ * Close VCC and notify owner
+ */
+ err = unisig_clear_vcc(usp, uvp,
+ T_ATM_CAUSE_NORMAL_CALL_CLEARING);
+ }
+
+ /*
+ * Set the signalling manager state
+ */
+ usp->us_state = UNISIG_DETACH;
+
+ /*
+ * Close the signalling channel
+ */
+ if (usp->us_conn) {
+ cause.coding_standard = T_ATM_ITU_CODING;
+ cause.coding_standard = T_ATM_LOC_USER;
+ cause.coding_standard = T_ATM_CAUSE_UNSPECIFIED_NORMAL;
+ err = atm_cm_release(usp->us_conn, &cause);
+ if (err)
+ panic("unisig_sigmgr_act14: close failed\n");
+ }
+
+ /*
+ * Get rid of protocol instance if there are no VCCs queued
+ */
+ pip = usp->us_pif;
+ if (Q_HEAD(usp->us_vccq, struct vccb) == NULL &&
+ pip->pif_sigmgr) {
+ struct sigmgr *smp = pip->pif_sigmgr;
+ int s = splimp();
+
+ pip->pif_sigmgr = NULL;
+ pip->pif_siginst = NULL;
+ (void) splx(s);
+
+ UNLINK((struct siginst *)usp, struct siginst,
+ smp->sm_prinst, si_next);
+ KM_FREE(usp, sizeof(struct unisig), M_DEVBUF);
+ }
+
+ /*
+ * Otherwise, wait for protocol instance to be freed
+ * during unisig_free processing for the last queued VCC
+ */
+
+ return (0);
+}
diff --git a/sys/netatm/uni/unisig_subr.c b/sys/netatm/uni/unisig_subr.c
new file mode 100644
index 0000000..f8dc067
--- /dev/null
+++ b/sys/netatm/uni/unisig_subr.c
@@ -0,0 +1,1276 @@
+/*
+ *
+ * ===================================
+ * 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: unisig_subr.c,v 1.12 1998/08/26 23:29:24 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI 3.0/3.1 Signalling Manager
+ * ----------------------------------------
+ *
+ * Subroutines
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: unisig_subr.c,v 1.12 1998/08/26 23:29:24 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/unisig.h>
+#include <netatm/uni/unisig_var.h>
+#include <netatm/uni/unisig_msg.h>
+
+
+/*
+ * External variables
+ */
+extern struct ie_aalp ie_aalp_absent;
+extern struct ie_clrt ie_clrt_absent;
+extern struct ie_bbcp ie_bbcp_absent;
+extern struct ie_bhli ie_bhli_absent;
+extern struct ie_blli ie_blli_absent;
+extern struct ie_clst ie_clst_absent;
+extern struct ie_cdad ie_cdad_absent;
+extern struct ie_cdsa ie_cdsa_absent;
+extern struct ie_cgad ie_cgad_absent;
+extern struct ie_cgsa ie_cgsa_absent;
+extern struct ie_caus ie_caus_absent;
+extern struct ie_cnid ie_cnid_absent;
+extern struct ie_qosp ie_qosp_absent;
+extern struct ie_brpi ie_brpi_absent;
+extern struct ie_rsti ie_rsti_absent;
+extern struct ie_blsh ie_blsh_absent;
+extern struct ie_bnsh ie_bnsh_absent;
+extern struct ie_bsdc ie_bsdc_absent;
+extern struct ie_trnt ie_trnt_absent;
+extern struct ie_eprf ie_eprf_absent;
+extern struct ie_epst ie_epst_absent;
+
+
+/*
+ * Set a cause code in an ATM attribute block
+ *
+ * Arguments:
+ * aap pointer to attribute block
+ * cause cause code
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+unisig_set_cause_attr(aap, cause)
+ Atm_attributes *aap;
+ int cause;
+{
+ /*
+ * Set the fields in the attribute block
+ */
+ aap->cause.tag = T_ATM_PRESENT;
+ aap->cause.v.coding_standard = T_ATM_ITU_CODING;
+ aap->cause.v.location = T_ATM_LOC_USER;
+ aap->cause.v.cause_value = cause;
+ KM_ZERO(aap->cause.v.diagnostics,
+ sizeof(aap->cause.v.diagnostics));
+}
+
+
+/*
+ * Open a UNI VCC
+ *
+ * Called when a user wants to open a VC. This function will construct
+ * a VCCB and, if we are opening an SVC, call the Q.2931 VC state
+ * machine. The user will have to wait for a notify event to be sure
+ * the SVC is fully open.
+ *
+ * Must be called at splnet.
+ *
+ * Arguments:
+ * usp pointer to UNISIG protocol instance
+ * cvp pointer to connection parameters for the VCC
+ *
+ * Returns:
+ * 0 VCC creation successful
+ * errno VCC setup failed - reason indicated
+ *
+ */
+int
+unisig_open_vcc(usp, cvp)
+ struct unisig *usp;
+ Atm_connvc *cvp;
+{
+ struct atm_pif *pip = usp->us_pif;
+ struct unisig_vccb *uvp;
+ Atm_addr_pvc *pvp;
+ int err, pvc;
+
+ ATM_DEBUG2("unisig_open_vcc: usp=0x%x, cvp=0x%x\n", usp, 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) {
+ 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;
+ if ((ATM_PVC_GET_VPI(pvp) > pip->pif_maxvpi) ||
+ (ATM_PVC_GET_VCI(pvp) == 0) ||
+ (ATM_PVC_GET_VCI(pvp) > pip->pif_maxvci)) {
+ return(ERANGE);
+ }
+
+ /*
+ * Make sure VPI/VCI is not already in use
+ */
+ if (unisig_find_vpvc(usp,
+ ATM_PVC_GET_VPI(pvp),
+ ATM_PVC_GET_VCI(pvp), 0)) {
+ return(EEXIST);
+ }
+ ATM_DEBUG2("unisig_open_vcc: VPI.VCI=%d.%d\n",
+ ATM_PVC_GET_VPI(pvp),
+ ATM_PVC_GET_VCI(pvp));
+ break;
+
+ case T_ATM_ENDSYS_ADDR:
+ /*
+ * Check signalling state
+ */
+ pvc = 0;
+ pvp = NULL;
+ if (usp->us_state != UNISIG_ACTIVE) {
+ return(ENETDOWN);
+ }
+
+ /*
+ * Make sure there's no subaddress
+ */
+ if (cvp->cvc_attr.called.subaddr.address_format !=
+ T_ATM_ABSENT) {
+ return(EINVAL);
+ }
+ break;
+
+ case T_ATM_E164_ADDR:
+ /*
+ * Check signalling state
+ */
+ pvc = 0;
+ pvp = NULL;
+ if (usp->us_state != UNISIG_ACTIVE) {
+ return(ENETDOWN);
+ }
+
+ /*
+ * Check destination address format
+ */
+ if (cvp->cvc_attr.called.subaddr.address_format !=
+ T_ATM_ENDSYS_ADDR &&
+ cvp->cvc_attr.called.subaddr.address_format !=
+ T_ATM_ABSENT) {
+ return(EINVAL);
+ }
+ break;
+
+ default:
+ return(EPROTONOSUPPORT);
+ }
+
+ /*
+ * Check that this is for the same interface UNISIG uses
+ */
+ if (!cvp->cvc_attr.nif ||
+ cvp->cvc_attr.nif->nif_pif != usp->us_pif) {
+ return(EINVAL);
+ }
+
+ /*
+ * Allocate control block for VCC
+ */
+ uvp = (struct unisig_vccb *)atm_allocate(&unisig_vcpool);
+ if (uvp == NULL) {
+ return(ENOMEM);
+ }
+
+ /*
+ * Fill in VCCB
+ */
+ if (pvc) {
+ uvp->uv_type = VCC_PVC | VCC_IN | VCC_OUT;
+ uvp->uv_vpi = ATM_PVC_GET_VPI(pvp);
+ uvp->uv_vci = ATM_PVC_GET_VCI(pvp);
+ uvp->uv_sstate = (usp->us_state == UNISIG_ACTIVE ?
+ UNI_PVC_ACTIVE : UNI_PVC_ACT_DOWN);
+ uvp->uv_ustate = VCCU_OPEN;
+ } else {
+ uvp->uv_type = VCC_SVC | VCC_IN | VCC_OUT;
+ uvp->uv_sstate = UNI_NULL;
+ uvp->uv_ustate = VCCU_POPEN;
+ }
+ uvp->uv_proto = usp->us_pif->pif_sigmgr->sm_proto;
+ uvp->uv_pif = usp->us_pif;
+ uvp->uv_nif = cvp->cvc_attr.nif;
+ uvp->uv_connvc = cvp;
+ uvp->uv_tstamp = time_second;
+
+ /*
+ * Put VCCB on UNISIG queue
+ */
+ ENQUEUE(uvp, struct unisig_vccb, uv_sigelem, usp->us_vccq);
+
+ /*
+ * Call the VC state machine if this is an SVC
+ */
+ if (!pvc) {
+ err = unisig_vc_state(usp, uvp, UNI_VC_SETUP_CALL,
+ (struct unisig_msg *) 0);
+ if (err) {
+ /*
+ * On error, delete the VCCB
+ */
+ DEQUEUE(uvp, struct unisig_vccb, uv_sigelem,
+ usp->us_vccq);
+ atm_free((caddr_t)uvp);
+ return(err);
+ }
+ }
+
+ /*
+ * Link VCCB to VCC connection block
+ */
+ cvp->cvc_vcc = (struct vccb *) uvp;
+
+ return(0);
+}
+
+
+/*
+ * Close a UNISIG 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:
+ * usp pointer to UNISIG protocol instance
+ * uvp pointer to VCCB for the VCC to be closed
+ *
+ * Returns:
+ * 0 VCC is now closed
+ * errno error encountered
+ */
+int
+unisig_close_vcc(usp, uvp)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+{
+ int err = 0;
+
+ ATM_DEBUG2("unisig_close_vcc: uvp=0x%x, state=%d\n", uvp,
+ uvp->uv_sstate);
+
+ /*
+ * Check that this is for the same interface UNISIG uses
+ */
+ if (uvp->uv_pif != usp->us_pif) {
+ return (EINVAL);
+ }
+
+ /*
+ * Mark the close time.
+ */
+ uvp->uv_tstamp = time_second;
+
+ /*
+ * Process based on the connection type
+ */
+ if (uvp->uv_type & VCC_PVC) {
+ uvp->uv_sstate = UNI_FREE;
+ uvp->uv_ustate = VCCU_CLOSED;
+ } else if (uvp->uv_type & VCC_SVC) {
+ /*
+ * Call the VC state machine
+ */
+ uvp->uv_ustate = VCCU_CLOSED;
+ err = unisig_vc_state(usp, uvp, UNI_VC_RELEASE_CALL,
+ (struct unisig_msg *) 0);
+ }
+
+ /*
+ * Wait for user to free resources
+ */
+ return(err);
+}
+
+
+/*
+ * Clear a UNISIG VCC
+ *
+ * Called to internally clear a VCC. No external protocol is
+ * initiated, the VCC is just closed and the owner is notified.
+ *
+ * Must be called at splnet.
+ *
+ * Arguments:
+ * usp pointer to UNISIG protocol instance
+ * uvp pointer to VCCB for the VCC to be closed
+ * cause cause code giving the reason for the close
+ *
+ * Returns:
+ * 0 VCC is closed
+ * errno error encountered
+ */
+int
+unisig_clear_vcc(usp, uvp, cause)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ int cause;
+{
+ u_char outstate;
+
+ ATM_DEBUG3("unisig_clear_vcc: uvp=0x%x, state=%d, cause=%d\n",
+ (int)uvp, uvp->uv_sstate, cause);
+
+ /*
+ * Check that this is for the same interface UNISIG uses
+ */
+ if (uvp->uv_pif != usp->us_pif) {
+ return (EINVAL);
+ }
+
+ /*
+ * Kill any possible timer
+ */
+ UNISIG_VC_CANCEL((struct vccb *) uvp);
+
+ /*
+ * Mark the close time.
+ */
+ uvp->uv_tstamp = time_second;
+
+ /*
+ * Close the VCC and notify the user
+ */
+ outstate = uvp->uv_sstate;
+ uvp->uv_sstate = UNI_FREE;
+ uvp->uv_ustate = VCCU_CLOSED;
+ if (outstate == UNI_ACTIVE ||
+ outstate == UNI_CALL_INITIATED ||
+ outstate == UNI_CALL_OUT_PROC ||
+ outstate == UNI_CONNECT_REQUEST ||
+ outstate == UNI_RELEASE_REQUEST ||
+ outstate == UNI_RELEASE_IND ||
+ outstate == UNI_SSCF_RECOV ||
+ outstate == UNI_PVC_ACT_DOWN ||
+ outstate == UNI_PVC_ACTIVE) {
+ unisig_set_cause_attr(&uvp->uv_connvc->cvc_attr, cause);
+ atm_cm_cleared(uvp->uv_connvc);
+ }
+
+ /*
+ * Wait for user to free resources
+ */
+ return(0);
+}
+
+
+#ifdef NOTDEF
+/*
+ * Reset the switch state
+ *
+ * Arguments:
+ * usp pointer to UNISIG protocol instance
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+unisig_switch_reset(usp, cause)
+ struct unisig *usp;
+ int cause;
+{
+ int s;
+ struct unisig_vccb *uvp, *vnext;
+
+ ATM_DEBUG2("unisig_switch_reset: usp=0x%x, cause=%d\n",
+ usp, cause);
+
+ /*
+ * Terminate all of our VCCs
+ */
+ s = splnet();
+ for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp;
+ uvp = vnext) {
+ vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem);
+
+ if (uvp->uv_type & VCC_SVC) {
+ /*
+ * Close the SVC and notify the owner
+ */
+ (void)unisig_clear_vcc(usp, uvp,
+ T_ATM_CAUSE_NORMAL_CALL_CLEARING);
+ } else if (uvp->uv_type & VCC_PVC) {
+ /*
+ * Notify PVC owner of the state change
+ */
+ switch(cause) {
+ case UNI_DOWN:
+ uvp->uv_sstate = UNI_PVC_ACT_DOWN;
+ break;
+ case UNI_UP:
+ uvp->uv_sstate = UNI_PVC_ACTIVE;
+ break;
+ }
+ atm_cm_cleared(uvp->uv_connvc, cause);
+ } else {
+ log(LOG_ERR, "unisig: invalid VCC type: vccb=0x%x, type=%d\n",
+ uvp, uvp->uv_type);
+ }
+ }
+ (void) splx(s);
+}
+#endif
+
+
+/*
+ * Copy connection parameters from UNI 3.0 message IEs into
+ * an attribute block
+ *
+ * Arguments:
+ * usp pointer to UNISIG protocol instance
+ * msg pointer to the SETUP message
+ * ap pointer to the attribute block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+unisig_save_attrs(usp, msg, ap)
+ struct unisig *usp;
+ struct unisig_msg *msg;
+ Atm_attributes *ap;
+{
+ /*
+ * Sanity check
+ */
+ if (!msg || !ap)
+ return;
+
+ /*
+ * Save the AAL parameters (AAL 3/4 and AAL 5 only)
+ */
+ if (msg->msg_ie_aalp) {
+ struct ie_generic *aalp = msg->msg_ie_aalp;
+
+ switch(msg->msg_ie_aalp->ie_aalp_aal_type) {
+ case UNI_IE_AALP_AT_AAL3:
+ ap->aal.tag = T_ATM_PRESENT;
+ ap->aal.type =
+ msg->msg_ie_aalp->ie_aalp_aal_type;
+ ap->aal.v.aal4.forward_max_SDU_size =
+ msg->msg_ie_aalp->ie_aalp_4_fwd_max_sdu;
+ ap->aal.v.aal4.backward_max_SDU_size =
+ msg->msg_ie_aalp->ie_aalp_4_bkwd_max_sdu;
+ ap->aal.v.aal4.SSCS_type =
+ msg->msg_ie_aalp->ie_aalp_4_sscs_type;
+ if (aalp->ie_aalp_4_mid_range == T_ATM_ABSENT) {
+ ap->aal.v.aal4.mid_low = T_ATM_ABSENT;
+ ap->aal.v.aal4.mid_high = T_ATM_ABSENT;
+ } else {
+ if (usp->us_proto == ATM_SIG_UNI30) {
+ ap->aal.v.aal4.mid_low = 0;
+ ap->aal.v.aal4.mid_high =
+ aalp->ie_aalp_4_mid_range
+ & UNI_IE_AALP_A3_R_MASK;
+ } else {
+ ap->aal.v.aal4.mid_low =
+ (aalp->ie_aalp_4_mid_range >>
+ UNI_IE_AALP_A3_R_SHIFT)
+ & UNI_IE_AALP_A3_R_MASK;
+ ap->aal.v.aal4.mid_high =
+ aalp->ie_aalp_4_mid_range
+ & UNI_IE_AALP_A3_R_MASK;
+ }
+ }
+ break;
+ case UNI_IE_AALP_AT_AAL5:
+ ap->aal.tag = T_ATM_PRESENT;
+ ap->aal.type =
+ msg->msg_ie_aalp->ie_aalp_aal_type;
+ ap->aal.v.aal5.forward_max_SDU_size =
+ msg->msg_ie_aalp->ie_aalp_5_fwd_max_sdu;
+ ap->aal.v.aal5.backward_max_SDU_size =
+ msg->msg_ie_aalp->ie_aalp_5_bkwd_max_sdu;
+ ap->aal.v.aal5.SSCS_type =
+ msg->msg_ie_aalp->ie_aalp_5_sscs_type;
+ break;
+ }
+ }
+
+ /*
+ * Save traffic descriptor attributes
+ */
+ if (msg->msg_ie_clrt) {
+ ap->traffic.tag = T_ATM_PRESENT;
+ ap->traffic.v.forward.PCR_high_priority =
+ msg->msg_ie_clrt->ie_clrt_fwd_peak;
+ ap->traffic.v.forward.PCR_all_traffic =
+ msg->msg_ie_clrt->ie_clrt_fwd_peak_01;
+ ap->traffic.v.forward.SCR_high_priority =
+ msg->msg_ie_clrt->ie_clrt_fwd_sust;
+ ap->traffic.v.forward.SCR_all_traffic =
+ msg->msg_ie_clrt->ie_clrt_fwd_sust_01;
+ ap->traffic.v.forward.MBS_high_priority =
+ msg->msg_ie_clrt->ie_clrt_fwd_burst;
+ ap->traffic.v.forward.MBS_all_traffic =
+ msg->msg_ie_clrt->ie_clrt_fwd_burst_01;
+ ap->traffic.v.backward.PCR_high_priority =
+ msg->msg_ie_clrt->ie_clrt_bkwd_peak;
+ ap->traffic.v.backward.PCR_all_traffic =
+ msg->msg_ie_clrt->ie_clrt_bkwd_peak_01;
+ ap->traffic.v.backward.SCR_high_priority =
+ msg->msg_ie_clrt->ie_clrt_bkwd_sust;
+ ap->traffic.v.backward.SCR_all_traffic =
+ msg->msg_ie_clrt->ie_clrt_bkwd_sust_01;
+ ap->traffic.v.backward.MBS_high_priority =
+ msg->msg_ie_clrt->ie_clrt_bkwd_burst;
+ ap->traffic.v.backward.MBS_all_traffic =
+ msg->msg_ie_clrt->ie_clrt_bkwd_burst_01;
+ ap->traffic.v.best_effort =
+ msg->msg_ie_clrt->ie_clrt_best_effort;
+ if (msg->msg_ie_clrt->ie_clrt_tm_options ==
+ T_ATM_ABSENT) {
+ ap->traffic.v.forward.tagging = T_NO;
+ ap->traffic.v.backward.tagging = T_NO;
+ } else {
+ ap->traffic.v.forward.tagging =
+ (msg->msg_ie_clrt->ie_clrt_tm_options &
+ UNI_IE_CLRT_TM_FWD_TAG) != 0;
+ ap->traffic.v.backward.tagging =
+ (msg->msg_ie_clrt->ie_clrt_tm_options &
+ UNI_IE_CLRT_TM_BKWD_TAG) != 0;
+ }
+ }
+
+ /*
+ * Save broadband bearer attributes
+ */
+ if (msg->msg_ie_bbcp) {
+ ap->bearer.tag = T_ATM_PRESENT;
+ ap->bearer.v.bearer_class =
+ msg->msg_ie_bbcp->ie_bbcp_bearer_class;
+ ap->bearer.v.traffic_type =
+ msg->msg_ie_bbcp->ie_bbcp_traffic_type;
+ ap->bearer.v.timing_requirements =
+ msg->msg_ie_bbcp->ie_bbcp_timing_req;
+ ap->bearer.v.clipping_susceptibility =
+ msg->msg_ie_bbcp->ie_bbcp_clipping;
+ ap->bearer.v.connection_configuration =
+ msg->msg_ie_bbcp->ie_bbcp_conn_config;
+ }
+
+ /*
+ * Save broadband high layer attributes
+ */
+ if (msg->msg_ie_bhli) {
+ ap->bhli.tag = T_ATM_PRESENT;
+ ap->bhli.v.ID_type = msg->msg_ie_bhli->ie_bhli_type;
+ switch(ap->bhli.v.ID_type) {
+ case T_ATM_ISO_APP_ID:
+ KM_COPY(msg->msg_ie_bhli->ie_bhli_info,
+ ap->bhli.v.ID.ISO_ID,
+ sizeof(ap->bhli.v.ID.ISO_ID));
+ break;
+ case T_ATM_USER_APP_ID:
+ KM_COPY(msg->msg_ie_bhli->ie_bhli_info,
+ ap->bhli.v.ID.user_defined_ID,
+ sizeof(ap->bhli.v.ID.user_defined_ID));
+ break;
+ case T_ATM_VENDOR_APP_ID:
+ KM_COPY(msg->msg_ie_bhli->ie_bhli_info,
+ ap->bhli.v.ID.vendor_ID.OUI,
+ sizeof(ap->bhli.v.ID.vendor_ID.OUI));
+ KM_COPY(&msg->msg_ie_bhli->ie_bhli_info[sizeof(ap->bhli.v.ID.vendor_ID.OUI)-1],
+ ap->bhli.v.ID.vendor_ID.app_ID,
+ sizeof(ap->bhli.v.ID.vendor_ID.app_ID));
+ break;
+ }
+ }
+
+ /*
+ * Save Broadband low layer, user layer 2 and 3 attributes
+ */
+ if (msg->msg_ie_blli) {
+ /*
+ * Layer 2 parameters
+ */
+ switch(msg->msg_ie_blli->ie_blli_l2_id) {
+ case UNI_IE_BLLI_L2P_ISO1745:
+ case UNI_IE_BLLI_L2P_Q921:
+ case UNI_IE_BLLI_L2P_X25L:
+ case UNI_IE_BLLI_L2P_X25M:
+ case UNI_IE_BLLI_L2P_LAPB:
+ case UNI_IE_BLLI_L2P_HDLC1:
+ case UNI_IE_BLLI_L2P_HDLC2:
+ case UNI_IE_BLLI_L2P_HDLC3:
+ case UNI_IE_BLLI_L2P_LLC:
+ case UNI_IE_BLLI_L2P_X75:
+ case UNI_IE_BLLI_L2P_Q922:
+ case UNI_IE_BLLI_L2P_ISO7776:
+ ap->blli.tag_l2 = T_ATM_PRESENT;
+ ap->blli.v.layer_2_protocol.ID_type =
+ T_ATM_SIMPLE_ID;
+ ap->blli.v.layer_2_protocol.ID.simple_ID =
+ msg->msg_ie_blli->ie_blli_l2_id;
+ break;
+ case UNI_IE_BLLI_L2P_USER:
+ ap->blli.tag_l2 = T_ATM_PRESENT;
+ ap->blli.v.layer_2_protocol.ID_type =
+ T_ATM_USER_ID;
+ ap->blli.v.layer_2_protocol.ID.user_defined_ID =
+ msg->msg_ie_blli->ie_blli_l2_user_proto;
+ break;
+ default:
+ ap->blli.tag_l2 = T_ATM_ABSENT;
+ }
+ if (ap->blli.tag_l2 == T_ATM_PRESENT) {
+ ap->blli.v.layer_2_protocol.mode =
+ msg->msg_ie_blli->ie_blli_l2_mode;
+ ap->blli.v.layer_2_protocol.window_size =
+ msg->msg_ie_blli->ie_blli_l2_window;
+ }
+
+ /*
+ * Layer 3 parameters
+ */
+ switch(msg->msg_ie_blli->ie_blli_l3_id) {
+ case UNI_IE_BLLI_L3P_X25:
+ case UNI_IE_BLLI_L3P_ISO8208:
+ case UNI_IE_BLLI_L3P_ISO8878:
+ case UNI_IE_BLLI_L3P_ISO8473:
+ case UNI_IE_BLLI_L3P_T70:
+ ap->blli.tag_l3 = T_ATM_PRESENT;
+ ap->blli.v.layer_3_protocol.ID_type =
+ T_ATM_SIMPLE_ID;
+ ap->blli.v.layer_3_protocol.ID.simple_ID =
+ msg->msg_ie_blli->ie_blli_l3_id;
+ break;
+ case UNI_IE_BLLI_L3P_ISO9577:
+ ap->blli.tag_l3 = T_ATM_PRESENT;
+ ap->blli.v.layer_3_protocol.ID_type =
+ T_ATM_SIMPLE_ID;
+ ap->blli.v.layer_3_protocol.ID.simple_ID =
+ msg->msg_ie_blli->ie_blli_l3_id;
+ if (msg->msg_ie_blli->ie_blli_l3_ipi ==
+ UNI_IE_BLLI_L3IPI_SNAP) {
+ KM_COPY(msg->msg_ie_blli->ie_blli_l3_oui,
+ ap->blli.v.layer_3_protocol.ID.SNAP_ID.OUI,
+ sizeof(ap->blli.v.layer_3_protocol.ID.SNAP_ID.OUI));
+ KM_COPY(msg->msg_ie_blli->ie_blli_l3_pid,
+ ap->blli.v.layer_3_protocol.ID.SNAP_ID.PID,
+ sizeof(ap->blli.v.layer_3_protocol.ID.SNAP_ID.PID));
+ } else {
+ ap->blli.v.layer_3_protocol.ID.IPI_ID =
+ msg->msg_ie_blli->ie_blli_l3_ipi;
+ }
+ break;
+ case UNI_IE_BLLI_L3P_USER:
+ ap->blli.tag_l3 = T_ATM_PRESENT;
+ ap->blli.v.layer_3_protocol.ID_type =
+ T_ATM_USER_ID;
+ ap->blli.v.layer_3_protocol.ID.user_defined_ID =
+ msg->msg_ie_blli->ie_blli_l3_user_proto;
+ break;
+ default:
+ ap->blli.tag_l3 = T_ATM_ABSENT;
+ }
+ if (ap->blli.tag_l3 == T_ATM_PRESENT) {
+ ap->blli.v.layer_3_protocol.mode =
+ msg->msg_ie_blli->ie_blli_l3_mode;
+ ap->blli.v.layer_3_protocol.packet_size =
+ msg->msg_ie_blli->ie_blli_l3_packet_size;
+ ap->blli.v.layer_3_protocol.window_size =
+ msg->msg_ie_blli->ie_blli_l3_window;
+ }
+ }
+
+ /*
+ * Save the called party address and subaddress
+ */
+ if (msg->msg_ie_cdad) {
+ ap->called.tag = T_ATM_PRESENT;
+ ATM_ADDR_COPY(&msg->msg_ie_cdad->ie_cdad_addr,
+ &ap->called.addr);
+ ap->called.subaddr.address_format = T_ATM_ABSENT;
+ ap->called.subaddr.address_length = 0;
+ }
+ if (msg->msg_ie_cdsa) {
+ ATM_ADDR_COPY(&msg->msg_ie_cdsa->ie_cdsa_addr,
+ &ap->called.subaddr);
+ }
+
+ /*
+ * Save the calling party address and subaddress
+ */
+ if (msg->msg_ie_cgad) {
+ ap->calling.tag = T_ATM_PRESENT;
+ ATM_ADDR_COPY(&msg->msg_ie_cgad->ie_cgad_addr,
+ &ap->calling.addr);
+ ap->calling.subaddr.address_format = T_ATM_ABSENT;
+ ap->calling.subaddr.address_length = 0;
+ }
+
+ if (msg->msg_ie_cgsa) {
+ ATM_ADDR_COPY(&msg->msg_ie_cgsa->ie_cgsa_addr,
+ &ap->calling.subaddr);
+ }
+
+ /*
+ * Save quality of service attributes
+ */
+ if (msg->msg_ie_qosp) {
+ ap->qos.tag = T_ATM_PRESENT;
+ ap->qos.v.coding_standard = msg->msg_ie_qosp->ie_coding;
+ ap->qos.v.forward.qos_class = msg->msg_ie_qosp->ie_qosp_fwd_class;
+ ap->qos.v.forward.qos_class =
+ msg->msg_ie_qosp->ie_qosp_bkwd_class;
+ }
+
+ /*
+ * Save transit network attributes
+ */
+ if (msg->msg_ie_trnt) {
+ ap->transit.tag = T_ATM_PRESENT;
+ ap->transit.v.length =
+ MIN(msg->msg_ie_trnt->ie_trnt_id_len,
+ sizeof(ap->transit.v.network_id));
+ KM_COPY(msg->msg_ie_trnt->ie_trnt_id,
+ ap->transit.v.network_id,
+ ap->transit.v.length);
+ }
+
+ /*
+ * Save cause code
+ */
+ if (msg->msg_ie_caus) {
+ ap->cause.tag = T_ATM_PRESENT;
+ ap->cause.v.coding_standard =
+ msg->msg_ie_caus->ie_coding;
+ ap->cause.v.location =
+ msg->msg_ie_caus->ie_caus_loc;
+ ap->cause.v.cause_value =
+ msg->msg_ie_caus->ie_caus_cause;
+ KM_ZERO(ap->cause.v.diagnostics,
+ sizeof(ap->cause.v.diagnostics));
+#ifdef NOTDEF
+ KM_COPY(msg->msg_ie_caus->ie_caus_diagnostic,
+ ap->transit.v.diagnostics,
+ MIN(sizeof(ap->transit.v.diagnostics),
+ msg->msg_ie_caus->ie_caus_diag_len));
+#endif
+ }
+}
+
+
+/*
+ * Copy connection parameters from an attribute block into
+ * UNI 3.0 message IEs
+ *
+ * Arguments:
+ * usp pointer to UNISIG protocol instance
+ * msg pointer to the SETUP message
+ * ap pointer to the attribute block
+ *
+ * Returns:
+ * 0 everything OK
+ * else error encountered
+ *
+ */
+int
+unisig_set_attrs(usp, msg, ap)
+ struct unisig *usp;
+ struct unisig_msg *msg;
+ Atm_attributes *ap;
+{
+ int err = 0;
+
+ /*
+ * Sanity check
+ */
+ if (!msg || !ap)
+ return(EINVAL);
+
+ /*
+ * Set the AAL parameters (AAL 3/4 and AAL 5 only)
+ */
+ if (ap->aal.tag == T_ATM_PRESENT) {
+ if (!msg->msg_ie_aalp) {
+ msg->msg_ie_aalp = (struct ie_generic *)
+ atm_allocate(&unisig_iepool);
+ if (msg->msg_ie_aalp == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+ }
+ KM_COPY(&ie_aalp_absent,
+ &msg->msg_ie_aalp->ie_u.ie_aalp,
+ sizeof(ie_aalp_absent));
+ msg->msg_ie_aalp->ie_ident = UNI_IE_AALP;
+ msg->msg_ie_aalp->ie_aalp_aal_type = ap->aal.type;
+ switch(ap->aal.type) {
+ case ATM_AAL3_4:
+ msg->msg_ie_aalp->ie_aalp_4_fwd_max_sdu =
+ ap->aal.v.aal4.forward_max_SDU_size;
+ msg->msg_ie_aalp->ie_aalp_4_bkwd_max_sdu =
+ ap->aal.v.aal4.backward_max_SDU_size;
+ msg->msg_ie_aalp->ie_aalp_4_mode = UNI_IE_AALP_A5_M_MSG;
+ msg->msg_ie_aalp->ie_aalp_4_sscs_type =
+ ap->aal.v.aal4.SSCS_type;
+ if (ap->aal.v.aal4.mid_low == T_ATM_ABSENT) {
+ msg->msg_ie_aalp->ie_aalp_4_mid_range =
+ T_ATM_ABSENT;
+ } else {
+ if (usp->us_proto == ATM_SIG_UNI30) {
+ msg->msg_ie_aalp->ie_aalp_4_mid_range =
+ ap->aal.v.aal4.mid_high &
+ UNI_IE_AALP_A3_R_MASK;
+ } else {
+ msg->msg_ie_aalp->ie_aalp_4_mid_range =
+ ((ap->aal.v.aal4.mid_low &
+ UNI_IE_AALP_A3_R_MASK)
+ << UNI_IE_AALP_A3_R_SHIFT)
+ |
+ (ap->aal.v.aal4.mid_high &
+ UNI_IE_AALP_A3_R_MASK);
+ }
+ }
+ break;
+ case ATM_AAL5:
+ msg->msg_ie_aalp->ie_aalp_5_fwd_max_sdu =
+ ap->aal.v.aal5.forward_max_SDU_size;
+ msg->msg_ie_aalp->ie_aalp_5_bkwd_max_sdu =
+ ap->aal.v.aal5.backward_max_SDU_size;
+ msg->msg_ie_aalp->ie_aalp_5_mode =
+ UNI_IE_AALP_A5_M_MSG;
+ msg->msg_ie_aalp->ie_aalp_5_sscs_type =
+ ap->aal.v.aal5.SSCS_type;
+ break;
+ }
+ }
+
+ /*
+ * Set traffic descriptor attributes
+ */
+ if (ap->traffic.tag == T_ATM_PRESENT) {
+ if (!msg->msg_ie_clrt) {
+ msg->msg_ie_clrt = (struct ie_generic *)
+ atm_allocate(&unisig_iepool);
+ if (msg->msg_ie_clrt == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+ }
+ KM_COPY(&ie_clrt_absent,
+ &msg->msg_ie_clrt->ie_u.ie_clrt,
+ sizeof(ie_clrt_absent));
+ msg->msg_ie_clrt->ie_ident = UNI_IE_CLRT;
+ msg->msg_ie_clrt->ie_clrt_fwd_peak =
+ ap->traffic.v.forward.PCR_high_priority;
+ msg->msg_ie_clrt->ie_clrt_fwd_peak_01 =
+ ap->traffic.v.forward.PCR_all_traffic;
+ msg->msg_ie_clrt->ie_clrt_fwd_sust =
+ ap->traffic.v.forward.SCR_high_priority;
+ msg->msg_ie_clrt->ie_clrt_fwd_sust_01 =
+ ap->traffic.v.forward.SCR_all_traffic;
+ msg->msg_ie_clrt->ie_clrt_fwd_burst =
+ ap->traffic.v.forward.MBS_high_priority;
+ msg->msg_ie_clrt->ie_clrt_fwd_burst_01 =
+ ap->traffic.v.forward.MBS_all_traffic;
+ msg->msg_ie_clrt->ie_clrt_bkwd_peak =
+ ap->traffic.v.backward.PCR_high_priority;
+ msg->msg_ie_clrt->ie_clrt_bkwd_peak_01 =
+ ap->traffic.v.backward.PCR_all_traffic;
+ msg->msg_ie_clrt->ie_clrt_bkwd_sust =
+ ap->traffic.v.backward.SCR_high_priority;
+ msg->msg_ie_clrt->ie_clrt_bkwd_sust_01 =
+ ap->traffic.v.backward.SCR_all_traffic;
+ msg->msg_ie_clrt->ie_clrt_bkwd_burst =
+ ap->traffic.v.backward.MBS_high_priority;
+ msg->msg_ie_clrt->ie_clrt_bkwd_burst_01 =
+ ap->traffic.v.backward.MBS_all_traffic;
+ msg->msg_ie_clrt->ie_clrt_best_effort =
+ ap->traffic.v.best_effort;
+ msg->msg_ie_clrt->ie_clrt_tm_options = 0;
+ if (ap->traffic.v.forward.tagging) {
+ msg->msg_ie_clrt->ie_clrt_tm_options |=
+ UNI_IE_CLRT_TM_FWD_TAG;
+ }
+ if (ap->traffic.v.backward.tagging) {
+ msg->msg_ie_clrt->ie_clrt_tm_options |=
+ UNI_IE_CLRT_TM_BKWD_TAG;
+ }
+ if (msg->msg_ie_clrt->ie_clrt_tm_options == 0) {
+ msg->msg_ie_clrt->ie_clrt_tm_options =
+ T_ATM_ABSENT;
+ }
+ }
+
+ /*
+ * Set broadband bearer attributes
+ */
+ if (ap->bearer.tag == T_ATM_PRESENT) {
+ if (!msg->msg_ie_bbcp) {
+ msg->msg_ie_bbcp = (struct ie_generic *)
+ atm_allocate(&unisig_iepool);
+ if (msg->msg_ie_bbcp == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+ }
+ KM_COPY(&ie_bbcp_absent,
+ &msg->msg_ie_bbcp->ie_u.ie_bbcp,
+ sizeof(ie_bbcp_absent));
+ msg->msg_ie_bbcp->ie_ident = UNI_IE_BBCP;
+ msg->msg_ie_bbcp->ie_bbcp_bearer_class =
+ ap->bearer.v.bearer_class;
+ msg->msg_ie_bbcp->ie_bbcp_traffic_type =
+ ap->bearer.v.traffic_type;
+ msg->msg_ie_bbcp->ie_bbcp_timing_req =
+ ap->bearer.v.timing_requirements;
+ msg->msg_ie_bbcp->ie_bbcp_clipping =
+ ap->bearer.v.clipping_susceptibility;
+ msg->msg_ie_bbcp->ie_bbcp_conn_config =
+ ap->bearer.v.connection_configuration;
+ }
+
+ /*
+ * Set broadband high layer attributes
+ */
+ if (ap->bhli.tag == T_ATM_PRESENT) {
+ if (!msg->msg_ie_bhli) {
+ msg->msg_ie_bhli = (struct ie_generic *)
+ atm_allocate(&unisig_iepool);
+ if (msg->msg_ie_bhli == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+ }
+ KM_COPY(&ie_bhli_absent,
+ &msg->msg_ie_bhli->ie_u.ie_bhli,
+ sizeof(ie_bhli_absent));
+ msg->msg_ie_bhli->ie_ident = UNI_IE_BHLI;
+ msg->msg_ie_bhli->ie_bhli_type = ap->bhli.v.ID_type;
+ switch (ap->bhli.v.ID_type) {
+ case T_ATM_ISO_APP_ID:
+ KM_COPY(ap->bhli.v.ID.ISO_ID,
+ msg->msg_ie_bhli->ie_bhli_info,
+ sizeof(ap->bhli.v.ID.ISO_ID));
+ break;
+ case T_ATM_USER_APP_ID:
+ KM_COPY(ap->bhli.v.ID.user_defined_ID,
+ msg->msg_ie_bhli->ie_bhli_info,
+ sizeof(ap->bhli.v.ID.user_defined_ID));
+ break;
+ case T_ATM_VENDOR_APP_ID:
+ KM_COPY(ap->bhli.v.ID.vendor_ID.OUI,
+ msg->msg_ie_bhli->ie_bhli_info,
+ sizeof(ap->bhli.v.ID.vendor_ID.OUI));
+ KM_COPY(ap->bhli.v.ID.vendor_ID.app_ID,
+ &msg->msg_ie_bhli->ie_bhli_info[sizeof(ap->bhli.v.ID.vendor_ID.OUI)-1],
+ sizeof(ap->bhli.v.ID.vendor_ID.app_ID));
+ break;
+ }
+ }
+
+ /*
+ * Set Broadband low layer, user layer 2 and 3 attributes
+ */
+ if (ap->blli.tag_l2 == T_ATM_PRESENT ||
+ ap->blli.tag_l3 == T_ATM_PRESENT) {
+ if (!msg->msg_ie_blli) {
+ msg->msg_ie_blli = (struct ie_generic *)
+ atm_allocate(&unisig_iepool);
+ if (msg->msg_ie_blli == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+ }
+ KM_COPY(&ie_blli_absent,
+ &msg->msg_ie_blli->ie_u.ie_blli,
+ sizeof(ie_blli_absent));
+ msg->msg_ie_blli->ie_ident = UNI_IE_BLLI;
+
+ if (ap->blli.tag_l2 == T_ATM_PRESENT) {
+ switch(ap->blli.v.layer_2_protocol.ID_type) {
+ case T_ATM_SIMPLE_ID:
+ msg->msg_ie_blli->ie_blli_l2_id =
+ ap->blli.v.layer_2_protocol.ID.simple_ID;
+ break;
+ case T_ATM_USER_ID:
+ msg->msg_ie_blli->ie_blli_l2_user_proto =
+ ap->blli.v.layer_2_protocol.ID.user_defined_ID;
+ break;
+ }
+ if (ap->blli.v.layer_2_protocol.ID_type !=
+ T_ATM_ABSENT) {
+ msg->msg_ie_blli->ie_blli_l2_mode =
+ ap->blli.v.layer_2_protocol.mode;
+ msg->msg_ie_blli->ie_blli_l2_window =
+ ap->blli.v.layer_2_protocol.window_size;
+ }
+ }
+
+ if (ap->blli.tag_l3 == T_ATM_PRESENT) {
+ switch (ap->blli.v.layer_3_protocol.ID_type) {
+ case T_ATM_SIMPLE_ID:
+ msg->msg_ie_blli->ie_blli_l3_id =
+ ap->blli.v.layer_3_protocol.ID.simple_ID;
+ break;
+
+ case T_ATM_IPI_ID:
+ msg->msg_ie_blli->ie_blli_l3_id =
+ UNI_IE_BLLI_L3P_ISO9577;
+ msg->msg_ie_blli->ie_blli_l3_ipi =
+ ap->blli.v.layer_3_protocol.ID.IPI_ID;
+ break;
+
+ case T_ATM_SNAP_ID:
+ msg->msg_ie_blli->ie_blli_l3_id =
+ UNI_IE_BLLI_L3P_ISO9577;
+ msg->msg_ie_blli->ie_blli_l3_ipi =
+ UNI_IE_BLLI_L3IPI_SNAP;
+ KM_COPY(ap->blli.v.layer_3_protocol.ID.SNAP_ID.OUI,
+ msg->msg_ie_blli->ie_blli_l3_oui,
+ sizeof(msg->msg_ie_blli->ie_blli_l3_oui));
+ KM_COPY(ap->blli.v.layer_3_protocol.ID.SNAP_ID.PID,
+ msg->msg_ie_blli->ie_blli_l3_pid,
+ sizeof(msg->msg_ie_blli->ie_blli_l3_pid));
+ break;
+
+ case T_ATM_USER_ID:
+ msg->msg_ie_blli->ie_blli_l3_id =
+ UNI_IE_BLLI_L3P_USER;
+ msg->msg_ie_blli->ie_blli_l3_user_proto =
+ ap->blli.v.layer_3_protocol.ID.user_defined_ID;
+ break;
+ }
+ if (ap->blli.v.layer_3_protocol.ID_type
+ != T_ATM_ABSENT) {
+ msg->msg_ie_blli->ie_blli_l3_mode =
+ ap->blli.v.layer_3_protocol.mode;
+ msg->msg_ie_blli->ie_blli_l3_packet_size =
+ ap->blli.v.layer_3_protocol.packet_size;
+ msg->msg_ie_blli->ie_blli_l3_window =
+ ap->blli.v.layer_3_protocol.window_size;
+ }
+ }
+ }
+
+ /*
+ * Set the called party address and subaddress
+ */
+ if (ap->called.tag == T_ATM_PRESENT) {
+ if (!msg->msg_ie_cdad) {
+ msg->msg_ie_cdad = (struct ie_generic *)
+ atm_allocate(&unisig_iepool);
+ if (msg->msg_ie_cdad == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+ }
+ KM_COPY(&ie_cdad_absent,
+ &msg->msg_ie_cdad->ie_u.ie_cdad,
+ sizeof(ie_cdad_absent));
+ msg->msg_ie_cdad->ie_ident = UNI_IE_CDAD;
+ ATM_ADDR_COPY(&ap->called.addr,
+ &msg->msg_ie_cdad->ie_cdad_addr);
+
+ if (ap->called.subaddr.address_format != T_ATM_ABSENT) {
+ if (!msg->msg_ie_cdsa) {
+ msg->msg_ie_cdsa = (struct ie_generic *)
+ atm_allocate(&unisig_iepool);
+ if (msg->msg_ie_cdsa == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+ }
+ KM_COPY(&ie_cdsa_absent,
+ &msg->msg_ie_cdsa->ie_u.ie_cdsa,
+ sizeof(ie_cdsa_absent));
+ msg->msg_ie_cdsa->ie_ident = UNI_IE_CDSA;
+ ATM_ADDR_COPY(&ap->called.subaddr,
+ &msg->msg_ie_cdsa->ie_cdsa_addr);
+ }
+ }
+
+ /*
+ * Set the calling party address and subaddress
+ */
+
+ if (ap->calling.tag == T_ATM_PRESENT) {
+ if (!msg->msg_ie_cgad) {
+ msg->msg_ie_cgad = (struct ie_generic *)
+ atm_allocate(&unisig_iepool);
+ if (msg->msg_ie_cgad == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+ }
+ KM_COPY(&ie_cgad_absent,
+ &msg->msg_ie_cgad->ie_u.ie_cgad,
+ sizeof(ie_cgad_absent));
+ msg->msg_ie_cgsa->ie_ident = UNI_IE_CGSA;
+ ATM_ADDR_COPY(&ap->calling.addr,
+ &msg->msg_ie_cgad->ie_cgad_addr);
+
+ if (ap->calling.subaddr.address_format !=
+ T_ATM_ABSENT) {
+ if (!msg->msg_ie_cgsa) {
+ msg->msg_ie_cgsa = (struct ie_generic *)
+ atm_allocate(&unisig_iepool);
+ if (msg->msg_ie_cgsa == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+ }
+ KM_COPY(&ie_cgsa_absent,
+ &msg->msg_ie_cgsa->ie_u.ie_cgsa,
+ sizeof(ie_cgsa_absent));
+ msg->msg_ie_cgsa->ie_ident = UNI_IE_CGSA;
+ ATM_ADDR_COPY(&ap->calling.subaddr,
+ &msg->msg_ie_cgsa->ie_cgsa_addr);
+ }
+ }
+
+ /*
+ * Set quality of service attributes
+ */
+ if (ap->qos.tag == T_ATM_PRESENT) {
+ if (!msg->msg_ie_qosp) {
+ msg->msg_ie_qosp = (struct ie_generic *)
+ atm_allocate(&unisig_iepool);
+ if (msg->msg_ie_qosp == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+ }
+ KM_COPY(&ie_qosp_absent,
+ &msg->msg_ie_qosp->ie_u.ie_qosp,
+ sizeof(ie_qosp_absent));
+ msg->msg_ie_qosp->ie_ident = UNI_IE_QOSP;
+ if (usp->us_proto == ATM_SIG_UNI30)
+ msg->msg_ie_qosp->ie_coding = UNI_IE_CODE_STD;
+ else if ((ap->qos.v.forward.qos_class ==
+ T_ATM_QOS_CLASS_0) ||
+ (ap->qos.v.backward.qos_class ==
+ T_ATM_QOS_CLASS_0))
+ msg->msg_ie_qosp->ie_coding = UNI_IE_CODE_CCITT;
+ else
+ msg->msg_ie_qosp->ie_coding = ap->qos.v.coding_standard;
+ msg->msg_ie_qosp->ie_qosp_fwd_class =
+ ap->qos.v.forward.qos_class;
+ msg->msg_ie_qosp->ie_qosp_bkwd_class =
+ ap->qos.v.backward.qos_class;
+ }
+
+ /*
+ * Set transit network attributes
+ */
+ if (ap->transit.tag == T_ATM_PRESENT &&
+ ap->transit.v.length != 0) {
+ if (!msg->msg_ie_trnt) {
+ msg->msg_ie_trnt = (struct ie_generic *)
+ atm_allocate(&unisig_iepool);
+ if (msg->msg_ie_trnt == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+ }
+ KM_COPY(&ie_trnt_absent,
+ &msg->msg_ie_trnt->ie_u.ie_trnt,
+ sizeof(ie_trnt_absent));
+ msg->msg_ie_trnt->ie_ident = UNI_IE_TRNT;
+ msg->msg_ie_trnt->ie_trnt_id_type =
+ UNI_IE_TRNT_IDT_NATL;
+ msg->msg_ie_trnt->ie_trnt_id_plan =
+ UNI_IE_TRNT_IDP_CIC;
+ KM_COPY(ap->transit.v.network_id,
+ msg->msg_ie_trnt->ie_trnt_id,
+ ap->transit.v.length);
+ }
+
+ /*
+ * Set cause code
+ */
+ if (ap->cause.tag == T_ATM_PRESENT) {
+ if (!msg->msg_ie_caus) {
+ msg->msg_ie_caus = (struct ie_generic *)
+ atm_allocate(&unisig_iepool);
+ if (msg->msg_ie_caus == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+ }
+ KM_COPY(&ie_caus_absent,
+ &msg->msg_ie_caus->ie_u.ie_caus,
+ sizeof(ie_caus_absent));
+ msg->msg_ie_caus->ie_ident = UNI_IE_CAUS;
+ msg->msg_ie_caus->ie_coding =
+ ap->cause.v.coding_standard;
+ msg->msg_ie_caus->ie_caus_loc =
+ ap->cause.v.location;
+ msg->msg_ie_caus->ie_caus_cause =
+ ap->cause.v.cause_value;
+
+ /*
+ * Don't copy the diagnostics from the attribute
+ * block, as there's no way to tell how much of
+ * the diagnostic field is relevant
+ */
+ msg->msg_ie_caus->ie_caus_diag_len = 0;
+ }
+
+done:
+ return(err);
+}
diff --git a/sys/netatm/uni/unisig_util.c b/sys/netatm/uni/unisig_util.c
new file mode 100644
index 0000000..ec4fbd0
--- /dev/null
+++ b/sys/netatm/uni/unisig_util.c
@@ -0,0 +1,389 @@
+/*
+ *
+ * ===================================
+ * 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: unisig_util.c,v 1.9 1998/08/26 23:29:24 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI 3.0/3.1 Signalling Manager
+ * ----------------------------------------
+ *
+ * Protocol processing module
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: unisig_util.c,v 1.9 1998/08/26 23:29:24 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/unisig.h>
+#include <netatm/uni/unisig_var.h>
+#include <netatm/uni/unisig_msg.h>
+
+
+/*
+ * Free a UNISIG signalling message
+ *
+ * Free the passed message and any IEs that are attached to it
+ *
+ * Arguments:
+ * msg pointer to UNISIG protocol instance
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+unisig_free_msg(msg)
+ struct unisig_msg *msg;
+{
+ int i;
+ struct ie_generic *ie, *ienxt;
+
+ ATM_DEBUG1("unisig_free_msg: msg=0x%x\n", msg);
+
+ /*
+ * First free all the IEs
+ */
+ for (i=0; i<UNI_MSG_IE_CNT; i++) {
+ ie = msg->msg_ie_vec[i];
+ while (ie) {
+ ienxt = ie->ie_next;
+ atm_free(ie);
+ ie = ienxt;
+ }
+ }
+
+ /*
+ * Finally, free the message structure itself
+ */
+ atm_free(msg);
+}
+
+
+/*
+ * Verify a VCCB
+ *
+ * Search UNISIG's VCCB queue to verify that a VCCB belongs to UNISIG.
+ *
+ * Arguments:
+ * usp pointer to UNISIG protocol instance
+ * svp pointer to a VCCB
+ *
+ * Returns:
+ * TRUE the VCCB belongs to UNISIG
+ * FALSE the VCCB doesn't belong to UNISIG
+ *
+ */
+int
+unisig_verify_vccb(usp, uvp)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+
+{
+ struct unisig_vccb *utp, *uvnext;
+
+ for (utp = Q_HEAD(usp->us_vccq, struct unisig_vccb);
+ utp; utp = uvnext){
+ uvnext = Q_NEXT(utp, struct unisig_vccb, uv_sigelem);
+ if (uvp == utp) {
+ return(TRUE);
+ }
+ }
+ return(FALSE);
+}
+
+
+/*
+ * Find a connection
+ *
+ * Find a VCCB given the call reference
+ *
+ * Arguments:
+ * usp pointer to UNISIG protocol instance
+ * cref the call reference to search for
+ *
+ * Returns:
+ * 0 there is no such VCCB
+ * uvp the address of the VCCB
+ *
+ */
+struct unisig_vccb *
+unisig_find_conn(usp, cref)
+ struct unisig *usp;
+ u_int cref;
+
+{
+ struct unisig_vccb *uvp, *uvnext;
+
+ for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp;
+ uvp = uvnext){
+ uvnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem);
+ if (uvp->uv_call_ref == cref)
+ break;
+ }
+ return(uvp);
+}
+
+
+/*
+ * Find a VCCB
+ *
+ * Find a VCCB given the VPI and VCI.
+ *
+ * Arguments:
+ * usp pointer to UNISIG 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
+ * uvp the address of the VCCB
+ *
+ */
+struct unisig_vccb *
+unisig_find_vpvc(usp, vpi, vci, dir)
+ struct unisig *usp;
+ int vpi, vci;
+ u_char dir;
+
+{
+ struct unisig_vccb *uvp, *uvnext;
+
+ for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp;
+ uvp = uvnext){
+ uvnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem);
+ if (uvp->uv_vpi == vpi &&
+ uvp->uv_vci == vci &&
+ (uvp->uv_type & dir) == dir)
+ break;
+ }
+ return(uvp);
+}
+
+
+/*
+ * Allocate a call reference value
+ *
+ * Arguments:
+ * usp pointer to UNISIG protocol instance
+ *
+ * Returns:
+ * 0 call reference not available
+ * cref the call reference value
+ *
+ */
+int
+unisig_alloc_call_ref(usp)
+ struct unisig *usp;
+
+{
+ int cref;
+
+ /*
+ * Get the next call reference value
+ */
+ cref = usp->us_cref;
+
+ /*
+ * Make sure it hasn't got too large
+ */
+ if (cref >= UNI_MSG_CALL_REF_DUMMY) {
+ /* XXX */
+ log(LOG_ERR, "uni: call reference limit reached\n");
+ return(0);
+ }
+
+ /*
+ * Bump the call reference value
+ */
+ usp->us_cref++;
+
+ return(cref);
+}
+
+
+/*
+ * Print an ATM address
+ *
+ * Convert an ATM address into an ASCII string suitable for printing.
+ *
+ * Arguments:
+ * p pointer to an ATM address
+ *
+ * Returns:
+ * the address of a string with the ASCII representation of the
+ * address. This routine returns the address of a statically-
+ * allocated buffer, so if repeated calls to this routine are made,
+ * each call will destroy the result of the previous call.
+ *
+ */
+char *
+unisig_addr_print(p)
+ Atm_addr *p;
+{
+ int i;
+ char *fp, *op, t_buff[16];
+ u_char *cp;
+ static char strbuff[256];
+
+ static char nf_DCC[] = "0xX.XX.X.XXX.XX.XX.XX.XXXXXX.X";
+ static char nf_ICD[] = "0xX.XX.X.XXX.XX.XX.XX.XXXXXX.X";
+ static char nf_E164[] = "0xX.XXXXXXXX.XX.XX.XXXXXX.X";
+
+ union {
+ int w;
+ char c[4];
+ } u1, u2;
+
+ /*
+ * Clear the print buffer
+ */
+ KM_ZERO(strbuff, sizeof(strbuff));
+
+ /*
+ * Select appropriate printing format
+ */
+ switch(p->address_format) {
+ case T_ATM_ENDSYS_ADDR:
+ /*
+ * Select format by NSAP type
+ */
+ switch(((Atm_addr_nsap *)p->address)->aan_afi) {
+ default:
+ case AFI_DCC:
+ fp = nf_DCC;
+ break;
+ case AFI_ICD:
+ fp = nf_ICD;
+ break;
+ case AFI_E164:
+ fp = nf_E164;
+ break;
+ }
+
+ /*
+ * Loop through the format string, converting the NSAP
+ * to ASCII
+ */
+ cp = (u_char *) p->address;
+ op = strbuff;
+ while (*fp) {
+ if (*fp == 'X') {
+ /*
+ * If format character is an 'X', put a
+ * two-digit hex representation of the
+ * NSAP byte in the output buffer
+ */
+ sprintf(t_buff, "%x", *cp + 512);
+ strcpy(op, &t_buff[strlen(t_buff)-2]);
+ op++; op++;
+ cp++;
+ } else {
+ /*
+ * If format character isn't an 'X',
+ * just copy it to the output buffer
+ */
+ *op = *fp;
+ op++;
+ }
+ fp++;
+ }
+
+ break;
+
+ case T_ATM_E164_ADDR:
+ /*
+ * Print the IA5 characters of the E.164 address
+ */
+ for(i=0; i<p->address_length; i++) {
+ sprintf(&strbuff[strlen(strbuff)], "%c\0",
+ ((Atm_addr_e164 *)p->address)->aae_addr[i]);
+ }
+ break;
+
+ case T_ATM_SPANS_ADDR:
+ /*
+ * Get address into integers
+ */
+ u1.c[0] = ((Atm_addr_spans *)p->address)->aas_addr[0];
+ u1.c[1] = ((Atm_addr_spans *)p->address)->aas_addr[1];
+ u1.c[2] = ((Atm_addr_spans *)p->address)->aas_addr[2];
+ u1.c[3] = ((Atm_addr_spans *)p->address)->aas_addr[3];
+ u2.c[0] = ((Atm_addr_spans *)p->address)->aas_addr[4];
+ u2.c[1] = ((Atm_addr_spans *)p->address)->aas_addr[5];
+ u2.c[2] = ((Atm_addr_spans *)p->address)->aas_addr[6];
+ u2.c[3] = ((Atm_addr_spans *)p->address)->aas_addr[7];
+
+ /*
+ * Print the address as two words xxxxx.yyyyyyyy
+ */
+ sprintf(strbuff, "%x.%x", u1.w, u2.w);
+ break;
+
+ case T_ATM_ABSENT:
+ default:
+ strcpy(strbuff, "-");
+ }
+
+ return(strbuff);
+}
+
+
+/*
+ * Print the contents of a message buffer chain
+ *
+ * Arguments:
+ * m pointer to a buffer
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+unisig_print_mbuf(m)
+ KBuffer *m;
+{
+ int i;
+ caddr_t cp;
+
+ printf("unisig_print_mbuf:\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/uni/unisig_var.h b/sys/netatm/uni/unisig_var.h
new file mode 100644
index 0000000..1e3d01a7
--- /dev/null
+++ b/sys/netatm/uni/unisig_var.h
@@ -0,0 +1,321 @@
+/*
+ *
+ * ===================================
+ * 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: unisig_var.h,v 1.12 1998/07/24 20:24:34 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI 3.0/3.1 Signalling Manager
+ * ----------------------------------------
+ *
+ * Protocol control blocks
+ *
+ */
+
+#ifndef _UNISIG_VAR_H
+#define _UNISIG_VAR_H
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#ifdef ATM_KERNEL
+/*
+ * Structure containing state information for each UNI protocol
+ * instance. There will be one instance for each ATM device interface
+ * using the UNI signalling manager.
+ */
+struct unisig {
+ struct siginst us_inst; /* Header */
+ struct atm_time us_time; /* Timer controls */
+ void (*us_lower) /* Lower command handler */
+ __P((int, void *, int, int));
+ Atm_connection *us_conn; /* Signalling connection */
+ int us_cref; /* Call reference allocation */
+ u_int us_retry; /* Protocol retry count */
+ u_short us_headout; /* Headroom on sig ch output */
+ u_char us_proto; /* Signalling version */
+};
+
+#define us_next us_inst.si_next
+#define us_pif us_inst.si_pif
+#define us_addr us_inst.si_addr
+#define us_subaddr us_inst.si_subaddr
+#define us_vccq us_inst.si_vccq
+#define us_state us_inst.si_state
+#define us_ipserv us_inst.si_ipserv
+#endif /* ATM_KERNEL */
+
+/*
+ * Signalling manager states
+ */
+#define UNISIG_NULL 0
+#define UNISIG_ADDR_WAIT 1
+#define UNISIG_INIT 2
+#define UNISIG_ACTIVE 3
+#define UNISIG_DETACH 4
+
+/*
+ * Signalling manager events
+ */
+#define UNISIG_SIGMGR_TIMEOUT 0
+#define UNISIG_SIGMGR_SSCF_EST_IND 1
+#define UNISIG_SIGMGR_SSCF_EST_CNF 2
+#define UNISIG_SIGMGR_SSCF_RLS_IND 3
+#define UNISIG_SIGMGR_SSCF_RLS_CNF 4
+#define UNISIG_SIGMGR_SSCF_DATA_IND 5
+#define UNISIG_SIGMGR_SSCF_UDATA_IND 6
+#define UNISIG_SIGMGR_CALL_CLEARED 7
+#define UNISIG_SIGMGR_DETACH 8
+#define UNISIG_SIGMGR_ADDR_SET 9
+
+/*
+ * Signalling manager timer values
+ */
+#define UNISIG_SSCF_TIMEOUT (3 * ATM_HZ)
+
+
+#ifdef ATM_KERNEL
+/*
+ * UNI Virtual Channel Connection control block. All information
+ * regarding the state of a UNI-controlled VCC will be recorded here.
+ * There will be one UNI VCC control block for each UNI-controlled
+ * VCC.
+ */
+struct unisig_vccb {
+ struct vccb vcp_hdr; /* Generic VCCB */
+ u_short uv_retry; /* Xmit retry count */
+ u_int uv_call_ref; /* Q.2931 call reference */
+};
+
+#define uv_type vcp_hdr.vc_type
+#define uv_proto vcp_hdr.vc_proto
+#define uv_sstate vcp_hdr.vc_sstate
+#define uv_ustate vcp_hdr.vc_ustate
+#define uv_pif vcp_hdr.vc_pif
+#define uv_nif vcp_hdr.vc_nif
+#define uv_sigelem vcp_hdr.vc_sigelem
+#define uv_time vcp_hdr.vc_time
+#define uv_vpi vcp_hdr.vc_vpi
+#define uv_vci vcp_hdr.vc_vci
+#define uv_connvc vcp_hdr.vc_connvc
+#define uv_ipdus vcp_hdr.vc_ipdus
+#define uv_opdus vcp_hdr.vc_opdus
+#define uv_ibytes vcp_hdr.vc_ibytes
+#define uv_obytes vcp_hdr.vc_obytes
+#define uv_ierrors vcp_hdr.vc_ierrors
+#define uv_oerrors vcp_hdr.vc_oerrors
+#define uv_tstamp vcp_hdr.vc_tstamp
+#endif /* ATM_KERNEL */
+
+/*
+ * UNI VCC protocol states. Taken from The ATM Forum UNI 3.0 (section
+ * 5.2.1.1)
+ */
+#define UNI_NULL 0 /* No call exists */
+#define UNI_CALL_INITIATED 1 /* Initiating call */
+#define UNI_CALL_OUT_PROC 3 /* Outgoing call proceeding */
+#define UNI_CALL_DELIVERED 4 /* Not supported */
+#define UNI_CALL_PRESENT 6 /* Call coming in */
+#define UNI_CALL_RECEIVED 7 /* Not supported */
+#define UNI_CONNECT_REQUEST 8 /* Call coming in */
+#define UNI_CALL_IN_PROC 9 /* Incoming call proceeding */
+#define UNI_ACTIVE 10 /* Call is established */
+#define UNI_RELEASE_REQUEST 11 /* Clearing call */
+#define UNI_RELEASE_IND 12 /* Network disconnecting */
+
+/*
+ * Additional states required for internal management of VCCs
+ */
+#define UNI_SSCF_RECOV 13 /* Signalling chan recovery */
+#define UNI_FREE 14 /* Waiting for user to free */
+#define UNI_PVC_ACTIVE 15 /* PVC Active */
+#define UNI_PVC_ACT_DOWN 16 /* PVC Active - i/f down */
+
+/*
+ * UNI VCC events
+ */
+#define UNI_VC_TIMEOUT 0 /* Timer expired */
+#define UNI_VC_CALLP_MSG 1 /* CALL PROCEEDING message */
+#define UNI_VC_CONNECT_MSG 2 /* CONNECT message */
+#define UNI_VC_CNCTACK_MSG 3 /* CONNECT ACK message */
+#define UNI_VC_SETUP_MSG 4 /* SETUP message */
+#define UNI_VC_RELEASE_MSG 5 /* RELEASE message */
+#define UNI_VC_RLSCMP_MSG 6 /* RELEASE COMPLETE message */
+#define UNI_VC_STATUS_MSG 7 /* STATUS message */
+#define UNI_VC_STATUSENQ_MSG 8 /* STATUS ENQ message */
+#define UNI_VC_ADDP_MSG 9 /* ADD PARTY message */
+#define UNI_VC_ADDPACK_MSG 10 /* ADD PARTY ACK message */
+#define UNI_VC_ADDPREJ_MSG 11 /* ADD PARTY REJ message */
+#define UNI_VC_DROP_MSG 12 /* DROP PARTY message */
+#define UNI_VC_DROPACK_MSG 13 /* DROP PARTY ACK message */
+#define UNI_VC_SETUP_CALL 14 /* Setup routine called */
+#define UNI_VC_ACCEPT_CALL 15 /* Accept call routine called */
+#define UNI_VC_REJECT_CALL 16 /* Reject call routine called */
+#define UNI_VC_RELEASE_CALL 17 /* Release routine called */
+#define UNI_VC_ABORT_CALL 18 /* Abort routine called */
+#define UNI_VC_SAAL_FAIL 19 /* Signalling AAL failed */
+#define UNI_VC_SAAL_ESTAB 20 /* Signalling AAL back up */
+
+
+#ifdef ATM_KERNEL
+/*
+ * UNI Timer Values. These values (except for T317) are taken from
+ * The ATM Forum UNI 3.0 (section 5.7.2).
+ */
+#define UNI_T303 (4 * ATM_HZ)
+#define UNI_T308 (30 * ATM_HZ)
+#define UNI_T309 (10 * ATM_HZ)
+#define UNI_T310 (10 * ATM_HZ)
+#define UNI_T313 (4 * ATM_HZ)
+#define UNI_T316 (120 * ATM_HZ)
+#define UNI_T317 (60 * ATM_HZ)
+#define UNI_T322 (4 * ATM_HZ)
+#define UNI_T398 (4 * ATM_HZ)
+#define UNI_T399 (14 * ATM_HZ)
+
+
+/*
+ * Timer macros
+ */
+#define UNISIG_TIMER(s, t) atm_timeout(&(s)->us_time, (t), unisig_timer)
+#define UNISIG_CANCEL(s) atm_untimeout(&(s)->us_time)
+#define UNISIG_VC_TIMER(v, t) atm_timeout(&(v)->vc_time, (t), unisig_vctimer)
+#define UNISIG_VC_CANCEL(v) atm_untimeout(&(v)->vc_time)
+
+
+/*
+ * Global function declarations
+ */
+struct usfmt;
+struct unisig_msg;
+
+ /* unisig_decode.c */
+int usf_dec_msg __P((struct usfmt *, struct unisig_msg *));
+
+ /* unisig_encode.c */
+int usf_enc_msg __P((struct usfmt *, struct unisig_msg *));
+
+ /* unisig_if.c */
+int unisig_start __P((void));
+int unisig_stop __P((void));
+int unisig_free __P((struct vccb *));
+
+ /* unisig_mbuf.c */
+int usf_init __P((struct usfmt *, struct unisig *, KBuffer *, int, int));
+int usf_byte __P((struct usfmt *, u_char *));
+int usf_short __P((struct usfmt *, u_short *));
+int usf_int3 __P((struct usfmt *, u_int *));
+int usf_int __P((struct usfmt *, u_int *));
+int usf_ext __P((struct usfmt *, u_int *));
+int usf_count __P((struct usfmt *));
+int usf_byte_mark __P((struct usfmt *, u_char *, u_char **));
+
+ /* unisig_msg.c */
+struct ie_generic;
+void unisig_cause_from_attr __P((struct ie_generic *,
+ Atm_attributes *));
+void unisig_cause_from_msg __P((struct ie_generic *,
+ struct unisig_msg *, int));
+int unisig_send_msg __P((struct unisig *,
+ struct unisig_msg *));
+int unisig_send_setup __P((struct unisig *,
+ struct unisig_vccb *));
+int unisig_send_release __P((struct unisig *,
+ struct unisig_vccb *,
+ struct unisig_msg *,
+ int));
+int unisig_send_release_complete __P((struct unisig *,
+ struct unisig_vccb *,
+ struct unisig_msg *,
+ int));
+int unisig_send_status __P((struct unisig *,
+ struct unisig_vccb *,
+ struct unisig_msg *,
+ int));
+int unisig_rcv_msg __P((struct unisig *, KBuffer *));
+
+ /* unisig_print.c */
+void usp_print_msg __P((struct unisig_msg *, int));
+
+ /* unisig_proto.c */
+void unisig_timer __P((struct atm_time *));
+void unisig_vctimer __P((struct atm_time *));
+void unisig_saal_ctl __P((int, void *, void *));
+void unisig_saal_data __P((void *, KBuffer *));
+caddr_t unisig_getname __P((void *));
+void unisig_connected __P((void *));
+void unisig_cleared __P((void *, struct t_atm_cause *));
+
+ /* unisig_sigmgr_state.c */
+int unisig_sigmgr_state __P((struct unisig *, int,
+ KBuffer *));
+
+ /* unisig_subr.c */
+void unisig_set_cause_attr __P((Atm_attributes *, int));
+int unisig_open_vcc __P((struct unisig *, Atm_connvc *));
+int unisig_close_vcc __P((struct unisig *,
+ struct unisig_vccb *));
+int unisig_clear_vcc __P((struct unisig *,
+ struct unisig_vccb *, int));
+void unisig_switch_reset __P((struct unisig *, int));
+void unisig_save_attrs __P((struct unisig *, struct unisig_msg *,
+ Atm_attributes *));
+int unisig_set_attrs __P((struct unisig *, struct unisig_msg *,
+ Atm_attributes *));
+
+ /* unisig_util.c */
+void unisig_free_msg __P((struct unisig_msg *));
+int unisig_verify_vccb __P((struct unisig *,
+ struct unisig_vccb *));
+struct unisig_vccb *
+ unisig_find_conn __P((struct unisig *, u_int));
+struct unisig_vccb *
+ unisig_find_vpvc __P((struct unisig *, int, int,
+ u_char));
+int unisig_alloc_call_ref __P((struct unisig *));
+char * unisig_addr_print __P((Atm_addr *));
+void unisig_print_mbuf __P((KBuffer *));
+void unisig_print_buffer __P((KBuffer *));
+
+ /* unisig_vc_state.c */
+int unisig_vc_state __P((struct unisig *,
+ struct unisig_vccb *,
+ int,
+ struct unisig_msg *));
+
+
+/*
+ * External variables
+ */
+extern struct sp_info unisig_vcpool;
+extern struct sp_info unisig_msgpool;
+extern struct sp_info unisig_iepool;
+
+#endif /* ATM_KERNEL */
+
+#endif /* _UNISIG_VAR_H */
diff --git a/sys/netatm/uni/unisig_vc_state.c b/sys/netatm/uni/unisig_vc_state.c
new file mode 100644
index 0000000..cfd7635
--- /dev/null
+++ b/sys/netatm/uni/unisig_vc_state.c
@@ -0,0 +1,2223 @@
+/*
+ *
+ * ===================================
+ * 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: unisig_vc_state.c,v 1.11 1998/08/06 18:16:29 mks Exp $
+ *
+ */
+
+/*
+ * ATM Forum UNI 3.0/3.1 Signalling Manager
+ * ----------------------------------------
+ *
+ * VC state machine
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: unisig_vc_state.c,v 1.11 1998/08/06 18:16:29 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include <netatm/uni/unisig.h>
+#include <netatm/uni/unisig_var.h>
+#include <netatm/uni/unisig_msg.h>
+#include <netatm/uni/unisig_mbuf.h>
+#include <netatm/uni/unisig_decode.h>
+
+
+/*
+ * Local functions
+ */
+static int unisig_vc_invalid __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act01 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act02 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act03 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act04 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act05 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act06 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act07 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act08 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act09 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act10 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act11 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act12 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act13 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act14 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act15 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act16 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act17 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act18 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act19 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act20 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act21 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act22 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act23 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act24 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act25 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act26 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act27 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act28 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act29 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act30 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_act31 __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *));
+static int unisig_vc_clear_call __P((struct unisig *,
+ struct unisig_vccb *,
+ struct unisig_msg *,
+ int));
+
+
+/*
+ * State table
+ */
+static int unisig_vc_states[21][17] = {
+/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 */
+{ 0, 2, 99, 5, 99, 99, 0, 99, 12, 99, 0, 14, 0, 3, 0, 0, 0 },
+{ 29, 4, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 },
+{ 29, 6, 99, 6, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 },
+{ 29, 17, 99, 17, 99, 99, 17, 99, 10, 99, 17, 17, 17, 0, 0, 0, 0 },
+{ 8, 17, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 },
+{ 29, 7, 99, 15, 99, 99, 15, 99, 15, 99, 15, 16, 17, 0, 0, 0, 0 },
+{ 19, 3, 99, 3, 99, 99, 3, 99, 3, 99, 3, 13, 3, 0, 0, 0, 0 },
+{ 21, 21, 99, 21, 99, 99, 21, 99, 21, 99, 21, 21, 21, 0, 0, 0, 0 },
+{ 22, 22, 99, 22, 99, 99, 22, 99, 22, 99, 22, 22, 22, 0, 0, 0, 0 },
+{ 29, 17, 99, 17, 99, 99, 17, 99, 17, 99, 23, 17, 17, 0, 0, 0, 0 },
+{ 29, 17, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 },
+{ 29, 17, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 },
+{ 29, 17, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 },
+{ 29, 17, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 },
+{ 1, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99 },
+{ 99, 25, 99, 25, 99, 99, 9, 99, 25, 99, 25, 25, 25, 25, 31, 25, 25 },
+{ 99, 25, 99, 25, 99, 99, 11, 99, 25, 99, 25, 25, 25, 25, 19, 25, 25 },
+{ 99, 12, 99, 12, 99, 99, 25, 99, 12, 99, 12, 19, 19, 30, 19, 99, 99 },
+{ 99, 12, 99, 12, 99, 99, 12, 99, 12, 99, 12, 3, 3, 3, 24, 26, 26 },
+{ 99, 3, 99, 3, 99, 99, 30, 99, 3, 99, 18, 3, 3, 0, 19, 27, 19 },
+{ 99, 7, 99, 7, 99, 99, 30, 99, 7, 99, 19, 19, 19, 20, 19, 19, 28 }
+};
+
+
+/*
+ * Action vector
+ *
+ * A given state, action pair selects an action number from the
+ * state table. This vector holds the address of the action routine
+ * for each action number.
+ */
+#define MAX_ACTION 32
+static int (*unisig_vc_act_vec[MAX_ACTION])
+ __P((struct unisig *, struct unisig_vccb *,
+ struct unisig_msg *)) = {
+ unisig_vc_invalid,
+ unisig_vc_act01,
+ unisig_vc_act02,
+ unisig_vc_act03,
+ unisig_vc_act04,
+ unisig_vc_act05,
+ unisig_vc_act06,
+ unisig_vc_act07,
+ unisig_vc_act08,
+ unisig_vc_act09,
+ unisig_vc_act10,
+ unisig_vc_act11,
+ unisig_vc_act12,
+ unisig_vc_act13,
+ unisig_vc_act14,
+ unisig_vc_act15,
+ unisig_vc_act16,
+ unisig_vc_act17,
+ unisig_vc_act18,
+ unisig_vc_act19,
+ unisig_vc_act20,
+ unisig_vc_act21,
+ unisig_vc_act22,
+ unisig_vc_act23,
+ unisig_vc_act24,
+ unisig_vc_act25,
+ unisig_vc_act26,
+ unisig_vc_act27,
+ unisig_vc_act28,
+ unisig_vc_act29,
+ unisig_vc_act30,
+ unisig_vc_act31
+};
+
+
+/*
+ * Process an event on a VC
+ *
+ * Arguments:
+ * usp pointer to the UNISIG instance
+ * uvp pointer to the VCCB for the affected VCC
+ * event a numeric indication of which event has occured
+ * msg pointer to a signalling message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+unisig_vc_state(usp, uvp, event, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ int event;
+ struct unisig_msg *msg;
+{
+ int action, rc, state;
+
+ /*
+ * Select an action from the state table
+ */
+ if (uvp)
+ state = uvp->uv_sstate;
+ else
+ state = UNI_NULL;
+ action = unisig_vc_states[event][state];
+ if (action >= MAX_ACTION || action < 0)
+ panic("unisig_vc_state: invalid action\n");
+
+ /*
+ * Perform the requested action
+ */
+ ATM_DEBUG4("unisig_vc_state: uvp=0x%x, state=%d, event=%d, action=%d\n",
+ (int) uvp, state, event, action);
+ rc = unisig_vc_act_vec[action](usp, uvp, msg);
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 0
+ * Unexpected action - log an error message
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection (may
+ be null)
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_invalid(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ log(LOG_ERR, "unisig_vc_state: unexpected action\n");
+ return(EINVAL);
+}
+
+
+/*
+ * VC state machine action 1
+ * Setup handler called
+ *
+ * Send SETUP, start timer T303, go to UNI_CALL_INITIATED state
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act01(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+
+ /*
+ * Send the setup message
+ */
+ rc = unisig_send_setup(usp, uvp);
+ if (rc)
+ return(rc);
+
+ /*
+ * Set timer T303
+ */
+ uvp->uv_retry = 0;
+ UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T303);
+
+ /*
+ * Set the new state
+ */
+ uvp->uv_sstate = UNI_CALL_INITIATED;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ return(0);
+}
+
+
+/*
+ * VC state machine action 2
+ * Timeout while waiting for CALL PROCEEDING or CONNECT
+ *
+ * If this is the second expiration, clear the call. Otherwise,
+ * retransmit the SETUP message and restart T303.
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act02(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc = 0;
+
+ if (uvp->uv_retry) {
+ /*
+ * Clear the call
+ */
+ rc = unisig_clear_vcc(usp, uvp,
+ T_ATM_CAUSE_NO_ROUTE_TO_DESTINATION);
+ } else {
+ uvp->uv_retry++;
+ (void) unisig_send_setup(usp, uvp);
+ UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T303);
+ }
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 3
+ *
+ * Clear the call internally
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act03(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+
+ /*
+ * Clear the VCCB
+ */
+ rc = unisig_clear_vcc(usp, uvp,
+ T_ATM_CAUSE_DESTINATION_OUT_OF_ORDER);
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 4
+ * Received CALL PROCEEDING
+ *
+ * Start timer T310, go to UNI_CALL_OUT_PROC
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act04(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int cause, rc, vpi, vci;
+ struct atm_pif *pip = usp->us_pif;
+ struct ie_generic *iep;
+
+ /*
+ * Clear any running timer
+ */
+ UNISIG_VC_CANCEL((struct vccb *) uvp);
+
+ /*
+ * Make sure a Connection ID is part of the message
+ */
+ if (msg->msg_ie_cnid) {
+ vpi = msg->msg_ie_cnid->ie_cnid_vpci;
+ vci = msg->msg_ie_cnid->ie_cnid_vci;
+ } else {
+ iep = (struct ie_generic *)atm_allocate(&unisig_iepool);
+ if (!iep)
+ return(ENOMEM);
+ iep->ie_ident = UNI_IE_CNID;
+ iep->ie_err_cause = UNI_IE_CAUS_MISSING;
+ MSG_IE_ADD(msg, iep, UNI_MSG_IE_ERR);
+ cause = UNI_IE_CAUS_MISSING;
+ ATM_DEBUG0("unisig_vc_act04: no CNID in Call Proc\n");
+ goto response04;
+ }
+
+ /*
+ * Make sure we can handle the specified VPI and VCI
+ */
+ if (vpi > pip->pif_maxvpi || vci > pip->pif_maxvci ||
+ vci < UNI_IE_CNID_MIN_VCI) {
+ cause = UNI_IE_CAUS_BAD_VCC;
+ ATM_DEBUG0("unisig_vc_act04: VPI/VCI invalid\n");
+ goto response04;
+ }
+
+ /*
+ * Make sure the specified VPI and VCI are not in use
+ */
+ if (unisig_find_vpvc(usp, vpi, vci, VCC_OUT)) {
+ cause = UNI_IE_CAUS_NA_VCC;
+ ATM_DEBUG0("unisig_vc_act04: VPI/VCI in use\n");
+ goto response04;
+ }
+
+ /*
+ * Start timer T310
+ */
+ UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T310);
+
+ /*
+ * Save the specified VPI and VCI
+ */
+ uvp->uv_vpi = vpi;
+ uvp->uv_vci = vci;
+
+ /*
+ * Set the state
+ */
+ uvp->uv_sstate = UNI_CALL_OUT_PROC;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ return(0);
+
+response04:
+ /*
+ * Initiate call clearing
+ */
+ rc = unisig_vc_clear_call(usp, uvp, msg, cause);
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 5
+ * Timeout in UNI_CALL_OUT_PROC
+ *
+ * Clear call towards network
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act05(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+ struct unisig_msg *rls_msg;
+ struct ie_generic *cause_ie;
+
+ /*
+ * Send a RELEASE message
+ */
+ rls_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
+ if (rls_msg == NULL)
+ return(ENOMEM);
+ cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
+ if (cause_ie == NULL) {
+ atm_free(rls_msg);
+ return(ENOMEM);
+ }
+
+ /*
+ * Fill out the RELEASE message
+ */
+ rls_msg->msg_call_ref = uvp->uv_call_ref;
+ rls_msg->msg_type = UNI_MSG_RLSE;
+ rls_msg->msg_type_flag = 0;
+ rls_msg->msg_type_action = 0;
+ rls_msg->msg_ie_caus = cause_ie;
+
+ /*
+ * Fill out the cause IE
+ */
+ cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER;
+ cause_ie->ie_caus_cause = UNI_IE_CAUS_TIMER;
+ KM_COPY("310", cause_ie->ie_caus_diagnostic, 3);
+
+ /*
+ * Send the RELEASE message.
+ */
+ rc = unisig_send_msg(usp, rls_msg);
+ unisig_free_msg(rls_msg);
+
+ /*
+ * Start timer T308
+ */
+ UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T308);
+
+ /*
+ * Set the new state
+ */
+ uvp->uv_sstate = UNI_RELEASE_REQUEST;
+ uvp->uv_ustate = VCCU_CLOSED;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 6
+ * Received CONNECT
+ *
+ * Send CONNECT ACK, go to UNI_ACTIVE state
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act06(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int cause, rc, vci, vpi;
+ struct atm_pif *pip = usp->us_pif;
+ struct unisig_msg *cack_msg;
+ struct ie_generic *iep;
+ Atm_attributes *ap;
+
+ /*
+ * Clear any running timer
+ */
+ UNISIG_VC_CANCEL((struct vccb *) uvp);
+
+ ap = &uvp->uv_connvc->cvc_attr;
+
+ /*
+ * See if a VPI/VCI is specified
+ */
+ if (msg->msg_ie_cnid) {
+ /*
+ * Yes--VPI/VCI must be the first specification or must
+ * match what was specified before
+ */
+ vpi = msg->msg_ie_cnid->ie_cnid_vpci;
+ vci = msg->msg_ie_cnid->ie_cnid_vci;
+ if ((uvp->uv_vpi || uvp->uv_vci) &&
+ (vpi != uvp->uv_vpi ||
+ vci != uvp->uv_vci)) {
+ cause = UNI_IE_CAUS_BAD_VCC;
+ ATM_DEBUG0("unisig_vc_act06: VPI/VCI invalid\n");
+ goto response06;
+ }
+
+ /*
+ * Specified VPI/VCI must be within range
+ */
+ if (vpi > pip->pif_maxvpi || vci > pip->pif_maxvci ||
+ vci < UNI_IE_CNID_MIN_VCI) {
+ cause = UNI_IE_CAUS_BAD_VCC;
+ ATM_DEBUG0("unisig_vc_act06: VPI/VCI invalid\n");
+ goto response06;
+ }
+ uvp->uv_vpi = vpi;
+ uvp->uv_vci = vci;
+ } else {
+ /*
+ * No--VPI/VCI must have been specified earlier
+ */
+ if (!uvp->uv_vpi || !uvp->uv_vci) {
+ iep = (struct ie_generic *)atm_allocate(
+ &unisig_iepool);
+ if (!iep)
+ return(ENOMEM);
+ iep->ie_ident = UNI_IE_CNID;
+ iep->ie_err_cause = UNI_IE_CAUS_MISSING;
+ MSG_IE_ADD(msg, iep, UNI_MSG_IE_ERR);
+ cause = UNI_IE_CAUS_MISSING;
+ ATM_DEBUG0("unisig_vc_act06: CNID missing\n");
+ goto response06;
+ }
+ }
+
+ /*
+ * Handle AAL parameters negotiation
+ */
+ if (msg->msg_ie_aalp) {
+ struct ie_generic *aalp = msg->msg_ie_aalp;
+
+ /*
+ * AAL parameters must have been sent in SETUP
+ */
+ if ((ap->aal.tag != T_ATM_PRESENT) ||
+ (ap->aal.type != aalp->ie_aalp_aal_type)) {
+ cause = UNI_IE_CAUS_IECONTENT;
+ goto response06;
+ }
+
+ switch (aalp->ie_aalp_aal_type) {
+
+ case UNI_IE_AALP_AT_AAL3:
+ /*
+ * Maximum SDU size negotiation
+ */
+ if (aalp->ie_aalp_4_fwd_max_sdu == T_ATM_ABSENT)
+ break;
+ if ((ap->aal.v.aal4.forward_max_SDU_size <
+ aalp->ie_aalp_4_fwd_max_sdu) ||
+ (ap->aal.v.aal4.backward_max_SDU_size <
+ aalp->ie_aalp_4_bkwd_max_sdu)) {
+ cause = UNI_IE_CAUS_IECONTENT;
+ goto response06;
+ } else {
+ ap->aal.v.aal4.forward_max_SDU_size =
+ aalp->ie_aalp_4_fwd_max_sdu;
+ ap->aal.v.aal4.backward_max_SDU_size =
+ aalp->ie_aalp_4_bkwd_max_sdu;
+ }
+ break;
+
+ case UNI_IE_AALP_AT_AAL5:
+ /*
+ * Maximum SDU size negotiation
+ */
+ if (aalp->ie_aalp_5_fwd_max_sdu == T_ATM_ABSENT)
+ break;
+ if ((ap->aal.v.aal5.forward_max_SDU_size <
+ aalp->ie_aalp_5_fwd_max_sdu) ||
+ (ap->aal.v.aal5.backward_max_SDU_size <
+ aalp->ie_aalp_5_bkwd_max_sdu)) {
+ cause = UNI_IE_CAUS_IECONTENT;
+ goto response06;
+ } else {
+ ap->aal.v.aal5.forward_max_SDU_size =
+ aalp->ie_aalp_5_fwd_max_sdu;
+ ap->aal.v.aal5.backward_max_SDU_size =
+ aalp->ie_aalp_5_bkwd_max_sdu;
+ }
+ break;
+ }
+ }
+
+ /*
+ * Get memory for a CONNECT ACK message
+ */
+ cack_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
+ if (cack_msg == NULL)
+ return(ENOMEM);
+
+ /*
+ * Fill out the CONNECT ACK message
+ */
+ cack_msg->msg_call_ref = uvp->uv_call_ref;
+ cack_msg->msg_type = UNI_MSG_CACK;
+ cack_msg->msg_type_flag = 0;
+ cack_msg->msg_type_action = 0;
+
+ /*
+ * Send the CONNECT ACK message
+ */
+ rc = unisig_send_msg(usp, cack_msg);
+ unisig_free_msg(cack_msg);
+
+ /*
+ * Set the new state
+ */
+ uvp->uv_sstate = UNI_ACTIVE;
+ uvp->uv_ustate = VCCU_OPEN;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ /*
+ * Notify the user that the connection is now active
+ */
+ atm_cm_connected(uvp->uv_connvc);
+
+ return(0);
+
+response06:
+ /*
+ * Initiate call clearing
+ */
+ rc = unisig_vc_clear_call(usp, uvp, msg, cause);
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 7
+ * Abort routine called or signalling SAAL session reset while in
+ * one of the call setup states
+ *
+ * Clear the call, send RELEASE COMPLETE, notify the user.
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act07(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+
+ /*
+ * Clear any running timer
+ */
+ UNISIG_VC_CANCEL((struct vccb *) uvp);
+
+ /*
+ * Send a RELEASE COMPLETE message rejecting the connection
+ */
+ rc = unisig_send_release_complete(usp, uvp, msg,
+ UNI_IE_CAUS_TEMP);
+
+ /*
+ * Clear the call VCCB
+ */
+ uvp->uv_sstate = UNI_FREE;
+ uvp->uv_ustate = VCCU_CLOSED;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ /*
+ * Notify the user
+ */
+ unisig_set_cause_attr(&uvp->uv_connvc->cvc_attr,
+ T_ATM_CAUSE_NORMAL_CALL_CLEARING);
+ atm_cm_cleared(uvp->uv_connvc);
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 8
+ * Received SETUP
+ *
+ * Check call paramaters, notify user that a call has been received,
+ * set UNI_CALL_PRESENT state
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act08(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int cause = 0, rc, vpi, vci;
+ struct atm_pif *pip = usp->us_pif;
+ struct atm_nif *nip;
+ Atm_addr_nsap *nap;
+ Atm_attributes attr;
+
+ ATM_DEBUG3("unisig_vc_act08: usp=0x%x, uvp=0x%x, msg=0x%x\n",
+ (int) usp, (int) uvp, (int) msg);
+
+ /*
+ * Make sure that the called address is the right format
+ */
+ if (msg->msg_ie_cdad->ie_cdad_plan != UNI_IE_CDAD_PLAN_NSAP) {
+ cause = UNI_IE_CAUS_IECONTENT;
+ ATM_DEBUG0("unisig_vc_act08: bad address format\n");
+ goto response08;
+ }
+
+ /*
+ * Make sure that the called address is ours
+ */
+ nap = (Atm_addr_nsap *) msg->msg_ie_cdad->ie_cdad_addr.address;
+ if (bcmp(usp->us_addr.address, nap, /* XXX */
+ sizeof(Atm_addr_nsap)-1)) {
+ cause = UNI_IE_CAUS_IECONTENT;
+ ATM_DEBUG0("unisig_vc_act08: address not mine\n");
+ goto response08;
+ }
+
+ /*
+ * Find the right NIF for the given selector byte
+ */
+ nip = pip->pif_nif;
+ while (nip && nip->nif_sel != nap->aan_sel) {
+ nip = nip->nif_pnext;
+ }
+ if (!nip) {
+ cause = UNI_IE_CAUS_IECONTENT;
+ ATM_DEBUG0("unisig_vc_act08: bad selector byte\n");
+ goto response08;
+ }
+
+ /*
+ * See if we can handle the specified encapsulation
+ */
+ if (msg->msg_ie_blli->ie_blli_l2_id != UNI_IE_BLLI_L2P_LLC &&
+ (msg->msg_ie_blli->ie_blli_l2_id != 0 ||
+ msg->msg_ie_blli->ie_blli_l3_id !=
+ UNI_IE_BLLI_L3P_ISO9577)) {
+ cause = UNI_IE_CAUS_UNAVAIL;
+ ATM_DEBUG0("unisig_vc_act08: bad encapsulation\n");
+ goto response08;
+ }
+
+ /*
+ * See if we recognize the specified AAL
+ */
+ if (msg->msg_ie_aalp->ie_aalp_aal_type != UNI_IE_AALP_AT_AAL3 &&
+ msg->msg_ie_aalp->ie_aalp_aal_type !=
+ UNI_IE_AALP_AT_AAL5) {
+ cause = UNI_IE_CAUS_UAAL;
+ ATM_DEBUG0("unisig_vc_act08: bad AAL\n");
+ goto response08;
+ }
+
+ /*
+ * Should verify that we can handle requested
+ * connection QOS
+ */
+
+ /*
+ * Make sure the specified VPI/VCI is valid
+ */
+ vpi = msg->msg_ie_cnid->ie_cnid_vpci;
+ vci = msg->msg_ie_cnid->ie_cnid_vci;
+ if (vpi > pip->pif_maxvpi ||
+ vci > pip->pif_maxvci ||
+ vci < UNI_IE_CNID_MIN_VCI) {
+ cause = UNI_IE_CAUS_BAD_VCC;
+ ATM_DEBUG0("unisig_vc_act08: VPI/VCI invalid\n");
+ goto response08;
+ }
+
+ /*
+ * Make sure the specified VPI/VCI isn't in use already
+ */
+ if (unisig_find_vpvc(usp, vpi, vci, VCC_IN)) {
+ cause = UNI_IE_CAUS_NA_VCC;
+ ATM_DEBUG0("unisig_vc_act08: VPI/VCI in use\n");
+ goto response08;
+ }
+
+ /*
+ * Make sure it's a point-to-point connection
+ */
+ if (msg->msg_ie_bbcp->ie_bbcp_conn_config !=
+ UNI_IE_BBCP_CC_PP) {
+ cause = UNI_IE_CAUS_NI_BC;
+ ATM_DEBUG0("unisig_vc_act08: conn not pt-pt\n");
+ goto response08;
+ }
+
+ /*
+ * Fill in the VCCB fields that we can at this point
+ */
+ uvp->uv_type = VCC_SVC | VCC_IN | VCC_OUT;
+ uvp->uv_proto = pip->pif_sigmgr->sm_proto;
+ uvp->uv_sstate = UNI_CALL_PRESENT;
+ uvp->uv_ustate = VCCU_POPEN;
+ uvp->uv_pif = pip;
+ uvp->uv_nif = nip;
+ uvp->uv_vpi = msg->msg_ie_cnid->ie_cnid_vpci;
+ uvp->uv_vci = msg->msg_ie_cnid->ie_cnid_vci;
+ uvp->uv_tstamp = time_second;
+
+ /*
+ * Copy the connection attributes from the SETUP message
+ * to an attribute block
+ */
+ KM_ZERO(&attr, sizeof(attr));
+ attr.nif = nip;
+ attr.aal.tag = T_ATM_ABSENT;
+ attr.traffic.tag = T_ATM_ABSENT;
+ attr.bearer.tag = T_ATM_ABSENT;
+ attr.bhli.tag = T_ATM_ABSENT;
+ attr.blli.tag_l2 = T_ATM_ABSENT;
+ attr.blli.tag_l3 = T_ATM_ABSENT;
+ attr.llc.tag = T_ATM_ABSENT;
+ attr.called.tag = T_ATM_ABSENT;
+ attr.calling.tag = T_ATM_ABSENT;
+ attr.qos.tag = T_ATM_ABSENT;
+ attr.transit.tag = T_ATM_ABSENT;
+ attr.cause.tag = T_ATM_ABSENT;
+ unisig_save_attrs(usp, msg, &attr);
+
+ /*
+ * Notify the connection manager of the new VCC
+ */
+ ATM_DEBUG0("unisig_vc_act08: notifying user of connection\n");
+ rc = atm_cm_incoming((struct vccb *)uvp, &attr);
+ if (rc)
+ goto response08;
+
+ /*
+ * Wait for the connection recipient to issue an accept
+ * or reject
+ */
+ return(0);
+
+response08:
+ ATM_DEBUG1("unisig_vc_act08: reject with cause=%d\n", cause);
+
+ /*
+ * Clear the VCCB state
+ */
+ uvp->uv_sstate = UNI_NULL;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ /*
+ * Some problem was detected with the request. Send a Q.2931
+ * message rejecting the connection.
+ */
+ rc = unisig_send_release_complete(usp, uvp, msg, cause);
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 9
+ * Accept routine called by user
+ *
+ * Send CONNECT, start timer T313, go to UNI_CONNECT_REQUEST state
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act09(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+ struct unisig_msg *conn_msg;
+
+ conn_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
+ if (conn_msg == NULL)
+ return(ENOMEM);
+
+ /*
+ * Fill out the response
+ */
+ conn_msg->msg_call_ref = uvp->uv_call_ref;
+ conn_msg->msg_type = UNI_MSG_CONN;
+ conn_msg->msg_type_flag = 0;
+ conn_msg->msg_type_action = 0;
+
+ /*
+ * Send the CONNECT message. If the send fails, the other
+ * side will eventually time out and close the connection.
+ */
+ rc = unisig_send_msg(usp, conn_msg);
+ unisig_free_msg(conn_msg);
+ if (rc) {
+ return(rc);
+ }
+
+ /*
+ * Start timer T313
+ */
+ UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T313);
+
+ /*
+ * Set the new state
+ */
+ uvp->uv_sstate = UNI_CONNECT_REQUEST;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ return(0);
+}
+
+
+/*
+ * VC state machine action 10
+ * Received CONNECT ACK
+ *
+ * Go to UNI_ACTIVE state
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act10(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ /*
+ * Clear any running timer
+ */
+ UNISIG_VC_CANCEL((struct vccb *) uvp);
+
+ /*
+ * Set the state
+ */
+ uvp->uv_sstate = UNI_ACTIVE;
+ uvp->uv_ustate = VCCU_OPEN;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ /*
+ * Notify the user that the call is up
+ */
+ atm_cm_connected(uvp->uv_connvc);
+
+ return (0);
+}
+
+
+/*
+ * VC state machine action 11
+ * Reject handler called
+ *
+ * Send RELEASE COMPLETE, clear the call
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act11(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+
+ /*
+ * Send a RELEASE COMPLETE message
+ */
+ rc = unisig_send_release_complete(usp, uvp, msg,
+ UNI_IE_CAUS_REJECT);
+
+ /*
+ * Clear the call VCCB
+ */
+ uvp->uv_sstate = UNI_FREE;
+ uvp->uv_ustate = VCCU_CLOSED;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 12
+ * Release or abort routine called
+ *
+ * Send RELEASE, start timer T308, go to UNI_RELEASE_REQUEST state
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act12(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+
+ /*
+ * Clear any running timer
+ */
+ UNISIG_VC_CANCEL((struct vccb *) uvp);
+
+ /*
+ * Send the RELEASE message
+ */
+ rc = unisig_vc_clear_call(usp, uvp, (struct unisig_msg *)0,
+ T_ATM_ABSENT);
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 13
+ * RELEASE COMPLETE received
+ *
+ * Clear the call
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act13(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ /*
+ * Clear any running timer
+ */
+ UNISIG_VC_CANCEL((struct vccb *) uvp);
+
+ /*
+ * Set the state
+ */
+ uvp->uv_sstate = UNI_FREE;
+ if (uvp->uv_ustate != VCCU_ABORT)
+ uvp->uv_ustate = VCCU_CLOSED;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ /*
+ * Notify the user that the call is now closed
+ */
+ unisig_set_cause_attr(&uvp->uv_connvc->cvc_attr,
+ T_ATM_CAUSE_NORMAL_CALL_CLEARING);
+ atm_cm_cleared(uvp->uv_connvc);
+
+ return(0);
+}
+
+
+/*
+ * VC state machine action 14
+ * Timer expired while waiting for RELEASE COMPLETE
+ *
+ * If this is the second expiration, just clear the call. Otherwise,
+ * retransmit the RELEASE message and restart timer T308.
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act14(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+
+ /*
+ * Check the retry count
+ */
+ if (uvp->uv_retry) {
+ /*
+ * Clear the connection
+ */
+ rc = unisig_clear_vcc(usp, uvp,
+ T_ATM_CAUSE_NORMAL_CALL_CLEARING);
+ } else {
+ /*
+ * Increment the retry count
+ */
+ uvp->uv_retry++;
+
+ /*
+ * Resend the RELEASE message
+ */
+ rc = unisig_send_release(usp, uvp,
+ (struct unisig_msg *)0, T_ATM_ABSENT);
+ if (rc)
+ return(rc);
+
+ /*
+ * Restart timer T308
+ */
+ UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T308);
+ }
+
+ return(0);
+}
+
+
+/*
+ * VC state machine action 15
+ * RELEASE received in UNI_ACTIVE state
+ *
+ * Send RELEASE COMPLETE, go to UNI_FREE, notify the user
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act15(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int cause, rc;
+ struct ie_generic *iep;
+
+ /*
+ * Clear any running timer
+ */
+ UNISIG_VC_CANCEL((struct vccb *) uvp);
+
+ /*
+ * If there was no Cause IE, flag an error
+ */
+ if (!msg->msg_ie_caus) {
+ cause = UNI_IE_CAUS_MISSING;
+ for (iep=msg->msg_ie_err; iep; iep=iep->ie_next) {
+ if (iep->ie_ident == UNI_IE_CAUS &&
+ iep->ie_err_cause ==
+ UNI_IE_CAUS_IECONTENT) {
+ cause = UNI_IE_CAUS_IECONTENT;
+ }
+ }
+ if (cause == UNI_IE_CAUS_MISSING) {
+ iep = (struct ie_generic *)atm_allocate(
+ &unisig_iepool);
+ if (!iep)
+ return(ENOMEM);
+ iep->ie_ident = UNI_IE_CNID;
+ iep->ie_err_cause = UNI_IE_CAUS_MISSING;
+ MSG_IE_ADD(msg, iep, UNI_MSG_IE_ERR);
+ }
+ } else {
+ cause = UNI_IE_CAUS_NORM_UNSP;
+ }
+
+ /*
+ * Send a RELEASE COMPLETE message
+ */
+ rc = unisig_send_release_complete(usp, uvp, msg, cause);
+
+ /*
+ * Set the state
+ */
+ uvp->uv_sstate = UNI_FREE;
+ uvp->uv_ustate = VCCU_CLOSED;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ /*
+ * Notify the user that the call is cleared
+ */
+ unisig_set_cause_attr(&uvp->uv_connvc->cvc_attr,
+ T_ATM_CAUSE_NORMAL_CALL_CLEARING);
+ atm_cm_cleared(uvp->uv_connvc);
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 16
+ * RELEASE received in UNI_RELEASE_REQUEST state
+ *
+ * Clear the call
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act16(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+
+ /*
+ * Clear any running timer
+ */
+ UNISIG_VC_CANCEL((struct vccb *) uvp);
+
+ /*
+ * Clear the VCCB
+ */
+ rc = unisig_clear_vcc(usp, uvp,
+ T_ATM_CAUSE_NORMAL_CALL_CLEARING);
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 17
+ * Protocol error
+ *
+ * Send a STATUS message with cause 101, "message not compatible with
+ * call state"
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act17(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+
+ ATM_DEBUG3("unisig_vc_perror: usp=0x%x, uvp=0x%x, msg=0x%x\n",
+ (int) usp, (int) uvp, (int) msg);
+
+ /*
+ * Clear any running timer
+ */
+ UNISIG_VC_CANCEL((struct vccb *) uvp);
+
+ /*
+ * Send a STATUS message
+ */
+ rc = unisig_send_status(usp, uvp, msg, UNI_IE_CAUS_STATE);
+
+ return(rc ? rc : EINVAL);
+}
+
+
+/*
+ * VC state machine action 18
+ * Signalling AAL connection has been lost
+ *
+ * Start timer T309. If the timer expires before the SAAL connection
+ * comes back, the VCC will be cleared.
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act18(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ /*
+ * Clear any running timer
+ */
+ UNISIG_VC_CANCEL((struct vccb *) uvp);
+
+ /*
+ * Start timer T309
+ */
+ UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T309);
+
+ /*
+ * Set new state
+ */
+ uvp->uv_sstate = UNI_SSCF_RECOV;
+
+ return(0);
+}
+
+
+/*
+ * VC state machine action 19
+ * Ignore the event
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act19(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ return(0);
+}
+
+
+/*
+ * VC state machine action 20
+ * SSCF establish indication in UNI_SSCF_RECOV state -- signalling
+ * AAL has come up after an outage
+ *
+ * Send STATUS ENQ to make sure we're in compatible state with other end
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act20(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+ struct unisig_msg *stat_msg;
+
+ /*
+ * Clear any running timer
+ */
+ UNISIG_VC_CANCEL((struct vccb *) uvp);
+
+ /*
+ * Get memory for a STATUS ENQUIRY message
+ */
+ stat_msg = (struct unisig_msg *)atm_allocate(&unisig_msgpool);
+ if (stat_msg == NULL)
+ return(ENOMEM);
+
+ /*
+ * Fill out the message
+ */
+ stat_msg->msg_call_ref = uvp->uv_call_ref;
+ stat_msg->msg_type = UNI_MSG_SENQ;
+ stat_msg->msg_type_flag = 0;
+ stat_msg->msg_type_action = 0;
+
+ /*
+ * Send the STATUS ENQUIRY message
+ */
+ rc = unisig_send_msg(usp, stat_msg);
+ unisig_free_msg(stat_msg);
+
+ /*
+ * Return to active state
+ */
+ uvp->uv_sstate = UNI_ACTIVE;
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 21
+ * STATUS received
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection (may
+ * be NULL)
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act21(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int cause, rc;
+
+ /*
+ * Ignore a STATUS message with the global call reference
+ */
+ if (GLOBAL_CREF(msg->msg_call_ref)) {
+ return(0);
+ }
+
+ /*
+ * If the network thinks we're in NULL state, clear the VCC
+ */
+ if (msg->msg_ie_clst->ie_clst_state == UNI_NULL) {
+ if (uvp) {
+ (void)unisig_clear_vcc(usp, uvp,
+ T_ATM_CAUSE_DESTINATION_OUT_OF_ORDER);
+ }
+ return(0);
+ }
+
+ /*
+ * If we are in NULL state, send a RELEASE COMPLETE
+ */
+ if (!uvp || (uvp->uv_sstate == UNI_FREE) ||
+ (uvp->uv_sstate == UNI_NULL)) {
+ rc = unisig_send_release_complete(usp,
+ uvp, msg, UNI_IE_CAUS_STATE);
+ return(rc);
+ }
+
+ /*
+ * If the reported state doesn't match our state, close the VCC
+ * unless we're in UNI_RELEASE_REQUEST or UNI_RELEASE_IND
+ */
+ if (msg->msg_ie_clst->ie_clst_state != uvp->uv_sstate) {
+ if (uvp->uv_sstate == UNI_RELEASE_REQUEST ||
+ uvp->uv_sstate == UNI_RELEASE_IND) {
+ return(0);
+ }
+ rc = unisig_clear_vcc(usp, uvp,
+ T_ATM_CAUSE_NORMAL_CALL_CLEARING);
+ }
+
+ /*
+ * States match, check for an error on one of our messages
+ */
+ cause = msg->msg_ie_caus->ie_caus_cause;
+ if (cause == UNI_IE_CAUS_MISSING ||
+ cause == UNI_IE_CAUS_MTEXIST ||
+ cause == UNI_IE_CAUS_IEEXIST ||
+ cause == UNI_IE_CAUS_IECONTENT ||
+ cause == UNI_IE_CAUS_STATE) {
+ ATM_DEBUG2("unisig_vc_act21: error %d on message 0x%x\n",
+ cause,
+ msg->msg_ie_caus->ie_caus_diagnostic[0]);
+ if (uvp) {
+ (void)unisig_clear_vcc(usp, uvp,
+ T_ATM_CAUSE_INVALID_INFO_ELEMENT_CONTENTS);
+ }
+ }
+
+ return(0);
+}
+
+
+/*
+ * VC state machine action 22
+ * Received STATUS ENQ
+ *
+ * Send STATUS with cause 30 "response to STATUS ENQUIRY" and
+ * current state
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection (may
+ * be NULL)
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act22(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+ struct unisig_msg *status;
+ struct ie_generic *callst_ie, *cause_ie;
+
+ ATM_DEBUG3("unisig_vc_perror: usp=0x%x, uvp=0x%x, msg=0x%x\n",
+ (int) usp, (int) uvp, (int) msg);
+
+ /*
+ * Get memory for a STATUS message
+ */
+ status = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
+ if (status == NULL)
+ return(ENOMEM);
+ callst_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
+ if (callst_ie == NULL) {
+ atm_free(status);
+ return(ENOMEM);
+ }
+ cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
+ if (cause_ie == NULL) {
+ atm_free(status);
+ atm_free(callst_ie);
+ return(ENOMEM);
+ }
+
+ /*
+ * Fill out the response
+ */
+ if (uvp) {
+ status->msg_call_ref = uvp->uv_call_ref;
+ } else if (msg) {
+ if (msg->msg_call_ref & UNI_MSG_CALL_REF_RMT)
+ status->msg_call_ref = msg->msg_call_ref &
+ UNI_MSG_CALL_REF_MASK;
+ else
+ status->msg_call_ref = msg->msg_call_ref |
+ UNI_MSG_CALL_REF_RMT;
+ } else {
+ status->msg_call_ref = UNI_MSG_CALL_REF_GLOBAL;
+ }
+ status->msg_type = UNI_MSG_STAT;
+ status->msg_type_flag = 0;
+ status->msg_type_action = 0;
+ status->msg_ie_clst = callst_ie;
+ status->msg_ie_caus = cause_ie;
+
+ /*
+ * Fill out the call state IE
+ */
+ callst_ie->ie_ident = UNI_IE_CLST;
+ callst_ie->ie_coding = 0;
+ callst_ie->ie_flag = 0;
+ callst_ie->ie_action = 0;
+ if (uvp) {
+ switch(uvp->uv_sstate) {
+ case UNI_FREE:
+ callst_ie->ie_clst_state = UNI_NULL;
+ break;
+ default:
+ callst_ie->ie_clst_state = uvp->uv_sstate;
+ }
+ } else {
+ callst_ie->ie_clst_state = UNI_NULL;
+ }
+
+ /*
+ * Fill out the cause IE
+ */
+ cause_ie->ie_ident = UNI_IE_CAUS;
+ cause_ie->ie_coding = 0;
+ cause_ie->ie_flag = 0;
+ cause_ie->ie_action = 0;
+ cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER;
+ cause_ie->ie_caus_cause = UNI_IE_CAUS_SENQ;
+
+ /*
+ * Send the STATUS message
+ */
+ rc = unisig_send_msg(usp, status);
+ unisig_free_msg(status);
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 23
+ * Received ADD PARTY
+ *
+ * We don't support multipoint connections, so send an ADD PARTY REJECT
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act23(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+ struct unisig_msg *apr_msg;
+
+ /*
+ * Get memory for the ADD PARTY REJECT message
+ */
+ apr_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
+ if (apr_msg == NULL)
+ return(ENOMEM);
+
+ /*
+ * Fill out the message
+ */
+ if (msg->msg_call_ref & UNI_MSG_CALL_REF_RMT)
+ apr_msg->msg_call_ref = msg->msg_call_ref &
+ UNI_MSG_CALL_REF_MASK;
+ else
+ apr_msg->msg_call_ref = msg->msg_call_ref |
+ UNI_MSG_CALL_REF_RMT;
+ apr_msg->msg_type = UNI_MSG_ADPR;
+ apr_msg->msg_type_flag = 0;
+ apr_msg->msg_type_action = 0;
+
+ /*
+ * Use the endpoint reference IE from the received message
+ */
+ apr_msg->msg_ie_eprf = msg->msg_ie_eprf;
+
+ /*
+ * Send the ADD PARTY REJECT message
+ */
+ rc = unisig_send_msg(usp, apr_msg);
+ apr_msg->msg_ie_eprf = NULL;
+ unisig_free_msg(apr_msg);
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 24
+ * User error
+ *
+ * Return EALREADY
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act24(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ return(EALREADY);
+}
+
+
+/*
+ * VC state machine action 25
+ * User error
+ *
+ * Return EINVAL
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act25(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ return(EINVAL);
+}
+
+
+/*
+ * VC state machine action 26
+ * PVC abort
+ *
+ * The abort handler was called to abort a PVC. Clear the VCCB and
+ * notify the user.
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act26(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+
+ /*
+ * Clear any running timer
+ */
+ UNISIG_VC_CANCEL((struct vccb *) uvp);
+
+ /*
+ * Close the VCCB
+ */
+ rc = unisig_close_vcc(usp, uvp);
+ if (rc)
+ return(rc);
+
+ /*
+ * Notify the user
+ */
+ unisig_set_cause_attr(&uvp->uv_connvc->cvc_attr,
+ T_ATM_CAUSE_NORMAL_CALL_CLEARING);
+ atm_cm_cleared(uvp->uv_connvc);
+
+ return(0);
+}
+
+
+/*
+ * VC state machine action 27
+ * Signalling AAL failure
+ *
+ * Change PVC state to UNI_PVC_ACT_DOWN.
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act27(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ /*
+ * Set the state
+ */
+ uvp->uv_sstate = UNI_PVC_ACT_DOWN;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ return(0);
+}
+
+
+/*
+ * VC state machine action 28
+ * Signalling AAL established
+ *
+ * Set PVC state to UNI_PVC_ACTIVE.
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act28(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ /*
+ * Set the state
+ */
+ uvp->uv_sstate = UNI_PVC_ACTIVE;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ return(0);
+}
+
+
+/*
+ * VC state machine action 29
+ * Protocol error
+ *
+ * Send a RELEASE COMPLETE message with cause 81, "invalid call
+ * reference value"
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection (may
+ * be NULL)
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act29(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ int rc;
+
+ /*
+ * Send a RELEASE COMPLETE message
+ */
+ rc = unisig_send_release_complete(usp, uvp, msg,
+ UNI_IE_CAUS_CREF);
+
+ return(rc);
+}
+
+
+/*
+ * VC state machine action 30
+ * Release routine called while SSCF session down, or SSCF session
+ * reset or lost while in UNI_CALL_PRESENT
+ *
+ * Go to UNI_FREE state
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act30(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ /*
+ * Clear any running timer
+ */
+ UNISIG_VC_CANCEL((struct vccb *) uvp);
+
+ /*
+ * Clear the call state
+ */
+ uvp->uv_sstate = UNI_FREE;
+ uvp->uv_ustate = VCCU_CLOSED;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ return(0);
+}
+
+
+/*
+ * VC state machine action 31
+ * Accept handler called in UNI_FREE state.
+ *
+ * The call was in UNI_CALL_PRESENT state when it was closed because
+ * of an SSCF failure. Return an error indication. The accept
+ * handler will free the VCCB and return the proper code to the
+ * caller.
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to a UNISIG message structure
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_act31(usp, uvp, msg)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+{
+ return(ENETDOWN);
+}
+
+
+/*
+ * Initiate clearing a call by sending a RELEASE message.
+ *
+ * Arguments:
+ * usp pointer to protocol instance block
+ * uvp pointer to the VCCB for the affected connection
+ * msg pointer to UNI signalling message that the RELEASE
+ * responds to (may be NULL)
+ * cause the reason for clearing the call; a value of
+ * T_ATM_ABSENT indicates that the cause code is
+ * in the VCC's ATM attributes block
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+static int
+unisig_vc_clear_call(usp, uvp, msg, cause)
+ struct unisig *usp;
+ struct unisig_vccb *uvp;
+ struct unisig_msg *msg;
+ int cause;
+{
+ int rc;
+
+ /*
+ * Clear the retry count
+ */
+ uvp->uv_retry = 0;
+
+ /*
+ * Make sure the ATM attributes block has a valid cause code,
+ * if needed
+ */
+ if (cause == T_ATM_ABSENT &&
+ uvp->uv_connvc->cvc_attr.cause.tag !=
+ T_ATM_PRESENT) {
+ uvp->uv_connvc->cvc_attr.cause.tag = T_ATM_PRESENT;
+ uvp->uv_connvc->cvc_attr.cause.v.coding_standard =
+ T_ATM_ITU_CODING;
+ uvp->uv_connvc->cvc_attr.cause.v.location =
+ T_ATM_LOC_USER;
+ uvp->uv_connvc->cvc_attr.cause.v.cause_value =
+ usp->us_proto == ATM_SIG_UNI30 ?
+ T_ATM_CAUSE_UNSPECIFIED_NORMAL :
+ T_ATM_CAUSE_NORMAL_CALL_CLEARING;
+ }
+
+ /*
+ * Send a RELEASE message
+ */
+ rc = unisig_send_release(usp, uvp, msg, cause);
+ if (rc)
+ return(rc);
+
+ /*
+ * Start timer T308
+ */
+ UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T308);
+
+ /*
+ * Set the VCCB state
+ */
+ uvp->uv_sstate = UNI_RELEASE_REQUEST;
+ if (uvp->uv_ustate != VCCU_ABORT)
+ uvp->uv_ustate = VCCU_CLOSED;
+
+ /*
+ * Mark the time
+ */
+ uvp->uv_tstamp = time_second;
+
+ return(0);
+}
OpenPOWER on IntegriCloud