summaryrefslogtreecommitdiffstats
path: root/sys/netatm/uni
diff options
context:
space:
mode:
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