summaryrefslogtreecommitdiffstats
path: root/sys/contrib/ngatm
diff options
context:
space:
mode:
authorharti <harti@FreeBSD.org>2003-10-22 07:41:16 +0000
committerharti <harti@FreeBSD.org>2003-10-22 07:41:16 +0000
commit9651c80ecbe05ee81acf5b9b0f9af21bf5814d01 (patch)
treebd99519d8e8aac11218a0706e357546610fd5b21 /sys/contrib/ngatm
downloadFreeBSD-src-9651c80ecbe05ee81acf5b9b0f9af21bf5814d01.zip
FreeBSD-src-9651c80ecbe05ee81acf5b9b0f9af21bf5814d01.tar.gz
Virgin import of the NgATM SAAL layer shared kernel/user part v0.9.
Diffstat (limited to 'sys/contrib/ngatm')
-rw-r--r--sys/contrib/ngatm/netnatm/misc/unimsg_common.c54
-rw-r--r--sys/contrib/ngatm/netnatm/saal/saal_sscfu.c577
-rw-r--r--sys/contrib/ngatm/netnatm/saal/saal_sscop.c4947
-rw-r--r--sys/contrib/ngatm/netnatm/saal/sscfu.h103
-rw-r--r--sys/contrib/ngatm/netnatm/saal/sscfudef.h73
-rw-r--r--sys/contrib/ngatm/netnatm/saal/sscfupriv.h66
-rw-r--r--sys/contrib/ngatm/netnatm/saal/sscop.h126
-rw-r--r--sys/contrib/ngatm/netnatm/saal/sscopdef.h154
-rw-r--r--sys/contrib/ngatm/netnatm/saal/sscoppriv.h308
-rw-r--r--sys/contrib/ngatm/netnatm/unimsg.h90
10 files changed, 6498 insertions, 0 deletions
diff --git a/sys/contrib/ngatm/netnatm/misc/unimsg_common.c b/sys/contrib/ngatm/netnatm/misc/unimsg_common.c
new file mode 100644
index 0000000..5d216a5
--- /dev/null
+++ b/sys/contrib/ngatm/netnatm/misc/unimsg_common.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2003-2003
+ * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Hartmut Brandt <harti@freebsd.org>
+ *
+ * $Begemot: libunimsg/atm/misc/unimsg_common.c,v 1.2 2003/09/19 12:05:45 hbb Exp $
+ */
+
+#include <netnatm/unimsg.h>
+
+/*
+ * Make sure there is enough space in front of the data for
+ * len bytes, and update the read pointer.
+ */
+int
+uni_msg_prepend(struct uni_msg *msg, size_t len)
+{
+ size_t need;
+
+ if (uni_msg_leading(msg) >= len) {
+ msg->b_rptr -= len;
+ return (0);
+ }
+ need = len - uni_msg_leading(msg);
+ if (uni_msg_ensure(msg, need))
+ return (-1);
+ memcpy(msg->b_rptr + need, msg->b_rptr, uni_msg_len(msg));
+ msg->b_rptr += need - len;
+ msg->b_wptr += need;
+ return (0);
+}
diff --git a/sys/contrib/ngatm/netnatm/saal/saal_sscfu.c b/sys/contrib/ngatm/netnatm/saal/saal_sscfu.c
new file mode 100644
index 0000000..a385b70
--- /dev/null
+++ b/sys/contrib/ngatm/netnatm/saal/saal_sscfu.c
@@ -0,0 +1,577 @@
+/*
+ * Copyright (c) 1996-2003
+ * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Hartmut Brandt <harti@freebsd.org>
+ *
+ * $Begemot: libunimsg/atm/saal/saal_sscfu.c,v 1.3 2003/09/19 12:02:03 hbb Exp $
+ *
+ * SSCF on the UNI
+ */
+
+#include <netnatm/saal/sscfu.h>
+#include <netnatm/saal/sscfupriv.h>
+
+#define MKSTR(S) #S
+
+static const char *const sscf_sigs[] = {
+ MKSTR(SAAL_ESTABLISH_request),
+ MKSTR(SAAL_ESTABLISH_indication),
+ MKSTR(SAAL_ESTABLISH_confirm),
+ MKSTR(SAAL_RELEASE_request),
+ MKSTR(SAAL_RELEASE_confirm),
+ MKSTR(SAAL_RELEASE_indication),
+ MKSTR(SAAL_DATA_request),
+ MKSTR(SAAL_DATA_indication),
+ MKSTR(SAAL_UDATA_request),
+ MKSTR(SAAL_UDATA_indication),
+};
+
+static const char *const sscf_states[] = {
+ MKSTR(SSCF_RELEASED),
+ MKSTR(SSCF_AWAITING_ESTABLISH),
+ MKSTR(SSCF_AWAITING_RELEASE),
+ MKSTR(SSCF_ESTABLISHED),
+ MKSTR(SSCF_RESYNC),
+};
+
+#define AA_SIG(S,G,M) \
+ ((S)->funcs->send_upper((S), (S)->aarg, (G), (M)))
+
+#define SSCOP_AASIG(S,G,M,P) \
+ ((S)->funcs->send_lower((S), (S)->aarg, (G), (M), (P)))
+
+MEMINIT();
+
+static void sscfu_unqueue(struct sscfu *sscf);
+
+/************************************************************/
+/*
+ * INSTANCE AND CLASS MANAGEMENT
+ */
+
+/*
+ * Initialize SSCF.
+ */
+struct sscfu *
+sscfu_create(void *a, const struct sscfu_funcs *funcs)
+{
+ struct sscfu *sscf;
+
+ MEMZALLOC(sscf, struct sscfu *, sizeof(struct sscfu));
+ if (sscf == NULL)
+ return (NULL);
+
+ sscf->funcs = funcs;
+ sscf->aarg = a;
+ sscf->state = SSCFU_RELEASED;
+ sscf->inhand = 0;
+ SIGQ_INIT(&sscf->sigs);
+ sscf->debug = 0;
+
+ return (sscf);
+}
+
+/*
+ * Reset the instance. Call only if you know, what you're doing.
+ */
+void
+sscfu_reset(struct sscfu *sscf)
+{
+ sscf->state = SSCFU_RELEASED;
+ sscf->inhand = 0;
+ SIGQ_CLEAR(&sscf->sigs);
+}
+
+/*
+ * Destroy SSCF
+ */
+void
+sscfu_destroy(struct sscfu *sscf)
+{
+ SIGQ_CLEAR(&sscf->sigs);
+ MEMFREE(sscf);
+}
+
+enum sscfu_state
+sscfu_getstate(const struct sscfu *sscf)
+{
+ return (sscf->state);
+}
+
+u_int
+sscfu_getdefparam(struct sscop_param *p)
+{
+ memset(p, 0, sizeof(*p));
+
+ p->timer_cc = 1000;
+ p->timer_poll = 750;
+ p->timer_keep_alive = 2000;
+ p->timer_no_response = 7000;
+ p->timer_idle = 15000;
+ p->maxk = 4096;
+ p->maxj = 4096;
+ p->maxcc = 4;
+ p->maxpd = 25;
+
+ return (SSCOP_SET_TCC | SSCOP_SET_TPOLL | SSCOP_SET_TKA |
+ SSCOP_SET_TNR | SSCOP_SET_TIDLE | SSCOP_SET_MAXK |
+ SSCOP_SET_MAXJ | SSCOP_SET_MAXCC | SSCOP_SET_MAXPD);
+}
+
+const char *
+sscfu_signame(enum saal_sig sig)
+{
+ static char str[40];
+
+ if (sig >= sizeof(sscf_sigs)/sizeof(sscf_sigs[0])) {
+ sprintf(str, "BAD SAAL_SIGNAL %u", sig);
+ return (str);
+ } else {
+ return (sscf_sigs[sig]);
+ }
+}
+
+const char *
+sscfu_statename(enum sscfu_state s)
+{
+ static char str[40];
+
+ if (s >= sizeof(sscf_states)/sizeof(sscf_states[0])) {
+ sprintf(str, "BAD SSCFU state %u", s);
+ return (str);
+ } else {
+ return (sscf_states[s]);
+ }
+}
+
+/************************************************************/
+/*
+ * EXTERNAL INPUT SIGNAL MAPPING
+ */
+static __inline void
+set_state(struct sscfu *sscf, enum sscfu_state state)
+{
+ VERBOSE(sscf, SSCFU_DBG_STATE, (sscf, sscf->aarg,
+ "change state from %s to %s",
+ sscf_states[sscf->state], sscf_states[state]));
+ sscf->state = state;
+}
+
+/*
+ * signal from SSCOP to SSCF
+ * Message must be freed by the user specified handler, if
+ * it is passed.
+ */
+void
+sscfu_input(struct sscfu *sscf, enum sscop_aasig sig,
+ struct SSCFU_MBUF_T *m, u_int arg __unused)
+{
+ sscf->inhand = 1;
+
+ VERBOSE(sscf, SSCFU_DBG_LSIG, (sscf, sscf->aarg,
+ "SSCF got signal %d. in state %s", sig, sscf_states[sscf->state]));
+
+ switch (sig) {
+
+ case SSCOP_RELEASE_indication:
+ /* arg is: UU, SRC */
+ switch (sscf->state) {
+
+ case SSCFU_RELEASED:
+ if (m)
+ MBUF_FREE(m);
+ goto badsig;
+
+ case SSCFU_AWAITING_ESTABLISH:
+ set_state(sscf, SSCFU_RELEASED);
+ AA_SIG(sscf, SAAL_RELEASE_indication, m);
+ break;
+
+ case SSCFU_AWAITING_RELEASE:
+ if (m)
+ MBUF_FREE(m);
+ goto badsig;
+
+ case SSCFU_ESTABLISHED:
+ set_state(sscf, SSCFU_RELEASED);
+ AA_SIG(sscf, SAAL_RELEASE_indication, m);
+ break;
+
+ case SSCFU_RESYNC:
+ set_state(sscf, SSCFU_RELEASED);
+ AA_SIG(sscf, SAAL_RELEASE_indication, m);
+ break;
+ }
+ break;
+
+ case SSCOP_ESTABLISH_indication:
+ /* arg is: UU */
+ switch (sscf->state) {
+
+ case SSCFU_RELEASED:
+ set_state(sscf, SSCFU_ESTABLISHED);
+ SSCOP_AASIG(sscf, SSCOP_ESTABLISH_response, NULL, 1);
+ AA_SIG(sscf, SAAL_ESTABLISH_indication, m);
+ break;
+
+ case SSCFU_AWAITING_ESTABLISH:
+ case SSCFU_AWAITING_RELEASE:
+ case SSCFU_ESTABLISHED:
+ case SSCFU_RESYNC:
+ if (m)
+ MBUF_FREE(m);
+ goto badsig;
+ }
+ break;
+
+ case SSCOP_ESTABLISH_confirm:
+ /* arg is: UU */
+ switch (sscf->state) {
+
+ case SSCFU_RELEASED:
+ if (m)
+ MBUF_FREE(m);
+ goto badsig;
+
+ case SSCFU_AWAITING_ESTABLISH:
+ set_state(sscf, SSCFU_ESTABLISHED);
+ AA_SIG(sscf, SAAL_ESTABLISH_confirm, m);
+ break;
+
+ case SSCFU_AWAITING_RELEASE:
+ case SSCFU_ESTABLISHED:
+ case SSCFU_RESYNC:
+ if (m)
+ MBUF_FREE(m);
+ goto badsig;
+ }
+ break;
+
+ case SSCOP_RELEASE_confirm:
+ /* arg is: */
+ switch (sscf->state) {
+
+ case SSCFU_RELEASED:
+ case SSCFU_AWAITING_ESTABLISH:
+ goto badsig;
+
+ case SSCFU_AWAITING_RELEASE:
+ set_state(sscf, SSCFU_RELEASED);
+ AA_SIG(sscf, SAAL_RELEASE_confirm, NULL);
+ break;
+
+ case SSCFU_ESTABLISHED:
+ case SSCFU_RESYNC:
+ goto badsig;
+ }
+ break;
+
+ case SSCOP_DATA_indication:
+ /* arg is: MU */
+ sscf->funcs->window(sscf, sscf->aarg, 1);
+ switch (sscf->state) {
+
+ case SSCFU_RELEASED:
+ case SSCFU_AWAITING_ESTABLISH:
+ case SSCFU_AWAITING_RELEASE:
+ MBUF_FREE(m);
+ goto badsig;
+
+ case SSCFU_ESTABLISHED:
+ AA_SIG(sscf, SAAL_DATA_indication, m);
+ break;
+
+ case SSCFU_RESYNC:
+ MBUF_FREE(m);
+ goto badsig;
+ }
+ break;
+
+ case SSCOP_RECOVER_indication:
+ /* arg is: */
+ switch (sscf->state) {
+
+ case SSCFU_RELEASED:
+ case SSCFU_AWAITING_ESTABLISH:
+ case SSCFU_AWAITING_RELEASE:
+ goto badsig;
+
+ case SSCFU_ESTABLISHED:
+ SSCOP_AASIG(sscf, SSCOP_RECOVER_response, NULL, 0);
+ AA_SIG(sscf, SAAL_ESTABLISH_indication, NULL);
+ break;
+
+ case SSCFU_RESYNC:
+ goto badsig;
+ }
+ break;
+
+ case SSCOP_RESYNC_indication:
+ /* arg is: UU */
+ switch (sscf->state) {
+
+ case SSCFU_RELEASED:
+ case SSCFU_AWAITING_ESTABLISH:
+ case SSCFU_AWAITING_RELEASE:
+ if (m)
+ MBUF_FREE(m);
+ goto badsig;
+
+ case SSCFU_ESTABLISHED:
+ SSCOP_AASIG(sscf, SSCOP_RESYNC_response, NULL, 0);
+ AA_SIG(sscf, SAAL_ESTABLISH_indication, m);
+ break;
+
+ case SSCFU_RESYNC:
+ if (m)
+ MBUF_FREE(m);
+ goto badsig;
+ }
+ break;
+
+ case SSCOP_RESYNC_confirm:
+ /* arg is: */
+ switch (sscf->state) {
+
+ case SSCFU_RELEASED:
+ case SSCFU_AWAITING_ESTABLISH:
+ case SSCFU_AWAITING_RELEASE:
+ case SSCFU_ESTABLISHED:
+
+ case SSCFU_RESYNC:
+ set_state(sscf, SSCFU_ESTABLISHED);
+ AA_SIG(sscf, SAAL_ESTABLISH_confirm, NULL);
+ break;
+ }
+ break;
+
+ case SSCOP_UDATA_indication:
+ /* arg is: MD */
+ AA_SIG(sscf, SAAL_UDATA_indication, m);
+ break;
+
+
+ case SSCOP_RETRIEVE_indication:
+ if (m)
+ MBUF_FREE(m);
+ goto badsig;
+
+ case SSCOP_RETRIEVE_COMPL_indication:
+ goto badsig;
+
+ case SSCOP_ESTABLISH_request:
+ case SSCOP_RELEASE_request:
+ case SSCOP_ESTABLISH_response:
+ case SSCOP_DATA_request:
+ case SSCOP_RECOVER_response:
+ case SSCOP_RESYNC_request:
+ case SSCOP_RESYNC_response:
+ case SSCOP_UDATA_request:
+ case SSCOP_RETRIEVE_request:
+ ASSERT(0);
+ break;
+ }
+
+ sscfu_unqueue(sscf);
+ return;
+
+ badsig:
+ VERBOSE(sscf, SSCFU_DBG_ERR, (sscf, sscf->aarg,
+ "bad signal %d. in state %s", sig, sscf_states[sscf->state]));
+ sscfu_unqueue(sscf);
+}
+
+
+/*
+ * Handle signals from the user
+ */
+static void
+sscfu_dosig(struct sscfu *sscf, enum saal_sig sig, struct SSCFU_MBUF_T *m)
+{
+ VERBOSE(sscf, SSCFU_DBG_EXEC, (sscf, sscf->aarg,
+ "executing signal %s(%s)",
+ sscf_sigs[sig], sscf_states[sscf->state]));
+
+ switch (sig) {
+
+ case SAAL_ESTABLISH_request:
+ /* arg is opt UU */
+ switch (sscf->state) {
+
+ case SSCFU_RELEASED:
+ set_state(sscf, SSCFU_AWAITING_ESTABLISH);
+ SSCOP_AASIG(sscf, SSCOP_ESTABLISH_request, m, 1);
+ break;
+
+ case SSCFU_AWAITING_ESTABLISH:
+ if (m)
+ MBUF_FREE(m);
+ goto badsig;
+
+ case SSCFU_AWAITING_RELEASE:
+ set_state(sscf, SSCFU_AWAITING_ESTABLISH);
+ SSCOP_AASIG(sscf, SSCOP_ESTABLISH_request, m, 1);
+ break;
+
+ case SSCFU_ESTABLISHED:
+ set_state(sscf, SSCFU_RESYNC);
+ SSCOP_AASIG(sscf, SSCOP_RESYNC_request, m, 0);
+ break;
+
+ case SSCFU_RESYNC:
+ if (m)
+ MBUF_FREE(m);
+ goto badsig;
+ }
+ break;
+
+ case SAAL_RELEASE_request:
+ /* arg is opt UU */
+ switch(sscf->state) {
+
+ case SSCFU_RELEASED:
+ if (m)
+ MBUF_FREE(m);
+ AA_SIG(sscf, SAAL_RELEASE_confirm, NULL);
+ break;
+
+ case SSCFU_AWAITING_ESTABLISH:
+ set_state(sscf, SSCFU_AWAITING_RELEASE);
+ SSCOP_AASIG(sscf, SSCOP_RELEASE_request, m, 0);
+ break;
+
+ case SSCFU_AWAITING_RELEASE:
+ if (m)
+ MBUF_FREE(m);
+ goto badsig;
+
+ case SSCFU_ESTABLISHED:
+ set_state(sscf, SSCFU_AWAITING_RELEASE);
+ SSCOP_AASIG(sscf, SSCOP_RELEASE_request, m, 0);
+ break;
+
+ case SSCFU_RESYNC:
+ set_state(sscf, SSCFU_AWAITING_RELEASE);
+ SSCOP_AASIG(sscf, SSCOP_RELEASE_request, m, 0);
+ break;
+ }
+ break;
+
+ case SAAL_DATA_request:
+ /* arg is DATA */
+ switch (sscf->state) {
+
+ case SSCFU_RELEASED:
+ case SSCFU_AWAITING_ESTABLISH:
+ case SSCFU_AWAITING_RELEASE:
+ MBUF_FREE(m);
+ goto badsig;
+
+ case SSCFU_ESTABLISHED:
+ SSCOP_AASIG(sscf, SSCOP_DATA_request, m, 0);
+ break;
+
+ case SSCFU_RESYNC:
+ MBUF_FREE(m);
+ goto badsig;
+ }
+ break;
+
+ case SAAL_UDATA_request:
+ /* arg is UDATA */
+ SSCOP_AASIG(sscf, SSCOP_UDATA_request, m, 0);
+ break;
+
+ case SAAL_ESTABLISH_indication:
+ case SAAL_ESTABLISH_confirm:
+ case SAAL_RELEASE_confirm:
+ case SAAL_RELEASE_indication:
+ case SAAL_DATA_indication:
+ case SAAL_UDATA_indication:
+ ASSERT(0);
+ break;
+ }
+ return;
+
+ badsig:
+ VERBOSE(sscf, SSCFU_DBG_ERR, (sscf, sscf->aarg,
+ "bad signal %s in state %s", sscf_sigs[sig],
+ sscf_states[sscf->state]));
+}
+
+/*
+ * Handle user signal.
+ */
+int
+sscfu_saalsig(struct sscfu *sscf, enum saal_sig sig, struct SSCFU_MBUF_T *m)
+{
+ struct sscfu_sig *s;
+
+ if (sscf->inhand) {
+ VERBOSE(sscf, SSCFU_DBG_EXEC, (sscf, sscf->aarg,
+ "queuing user signal %s(%s)",
+ sscf_sigs[sig], sscf_states[sscf->state]));
+ SIG_ALLOC(s);
+ if (s == NULL)
+ return (ENOMEM);
+ s->sig = sig;
+ s->m = m;
+ SIGQ_APPEND(&sscf->sigs, s);
+ return (0);
+ }
+
+ sscf->inhand = 1;
+ sscfu_dosig(sscf, sig, m);
+ sscfu_unqueue(sscf);
+ return (0);
+}
+
+/*
+ * Unqueue all qeueued signals. Must be called with inhand==1.
+ */
+static void
+sscfu_unqueue(struct sscfu *sscf)
+{
+ struct sscfu_sig *s;
+
+ while ((s = SIGQ_GET(&sscf->sigs)) != NULL) {
+ sscfu_dosig(sscf, s->sig, s->m);
+ SIG_FREE(s);
+ }
+ sscf->inhand = 0;
+}
+
+void
+sscfu_setdebug(struct sscfu *sscf, u_int n)
+{
+ sscf->debug = n;
+}
+
+u_int
+sscfu_getdebug(const struct sscfu *sscf)
+{
+ return (sscf->debug);
+}
diff --git a/sys/contrib/ngatm/netnatm/saal/saal_sscop.c b/sys/contrib/ngatm/netnatm/saal/saal_sscop.c
new file mode 100644
index 0000000..7a62505
--- /dev/null
+++ b/sys/contrib/ngatm/netnatm/saal/saal_sscop.c
@@ -0,0 +1,4947 @@
+/*
+ * Copyright (c) 1996-2003
+ * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Hartmut Brandt <harti@freebsd.org>
+ *
+ * $Begemot: libunimsg/atm/saal/saal_sscop.c,v 1.10 2003/09/19 12:02:03 hbb Exp $
+ *
+ * Core SSCOP code (ITU-T Q.2110)
+ */
+
+#include <netnatm/saal/sscop.h>
+#include <netnatm/saal/sscoppriv.h>
+
+#ifndef FAILURE
+#define FAILURE(S)
+#endif
+
+#define MKSTR(S) #S
+
+static const char *const sscop_sigs[] = {
+ MKSTR(SSCOP_ESTABLISH_request),
+ MKSTR(SSCOP_ESTABLISH_indication),
+ MKSTR(SSCOP_ESTABLISH_response),
+ MKSTR(SSCOP_ESTABLISH_confirm),
+ MKSTR(SSCOP_RELEASE_request),
+ MKSTR(SSCOP_RELEASE_indication),
+ MKSTR(SSCOP_RELEASE_confirm),
+ MKSTR(SSCOP_DATA_request),
+ MKSTR(SSCOP_DATA_indication),
+ MKSTR(SSCOP_UDATA_request),
+ MKSTR(SSCOP_UDATA_indication),
+ MKSTR(SSCOP_RECOVER_indication),
+ MKSTR(SSCOP_RECOVER_response),
+ MKSTR(SSCOP_RESYNC_request),
+ MKSTR(SSCOP_RESYNC_indication),
+ MKSTR(SSCOP_RESYNC_response),
+ MKSTR(SSCOP_RESYNC_confirm),
+ MKSTR(SSCOP_RETRIEVE_request),
+ MKSTR(SSCOP_RETRIEVE_indication),
+ MKSTR(SSCOP_RETRIEVE_COMPL_indication),
+};
+
+static const char *const sscop_msigs[] = {
+ MKSTR(SSCOP_MDATA_request),
+ MKSTR(SSCOP_MDATA_indication),
+ MKSTR(SSCOP_MERROR_indication),
+};
+
+static const char *const states[] = {
+ MKSTR(SSCOP_IDLE),
+ MKSTR(SSCOP_OUT_PEND),
+ MKSTR(SSCOP_IN_PEND),
+ MKSTR(SSCOP_OUT_DIS_PEND),
+ MKSTR(SSCOP_OUT_RESYNC_PEND),
+ MKSTR(SSCOP_IN_RESYNC_PEND),
+ MKSTR(SSCOP_OUT_REC_PEND),
+ MKSTR(SSCOP_REC_PEND),
+ MKSTR(SSCOP_IN_REC_PEND),
+ MKSTR(SSCOP_READY),
+};
+
+#ifdef SSCOP_DEBUG
+static const char *const events[] = {
+ MKSTR(SIG_BGN),
+ MKSTR(SIG_BGAK),
+ MKSTR(SIG_END),
+ MKSTR(SIG_ENDAK),
+ MKSTR(SIG_RS),
+ MKSTR(SIG_RSAK),
+ MKSTR(SIG_BGREJ),
+ MKSTR(SIG_SD),
+ MKSTR(SIG_ER),
+ MKSTR(SIG_POLL),
+ MKSTR(SIG_STAT),
+ MKSTR(SIG_USTAT),
+ MKSTR(SIG_UD),
+ MKSTR(SIG_MD),
+ MKSTR(SIG_ERAK),
+
+ MKSTR(SIG_T_CC),
+ MKSTR(SIG_T_POLL),
+ MKSTR(SIG_T_KA),
+ MKSTR(SIG_T_NR),
+ MKSTR(SIG_T_IDLE),
+
+ MKSTR(SIG_PDU_Q),
+ MKSTR(SIG_USER_DATA),
+ MKSTR(SIG_ESTAB_REQ),
+ MKSTR(SIG_ESTAB_RESP),
+ MKSTR(SIG_RELEASE_REQ),
+ MKSTR(SIG_RECOVER),
+ MKSTR(SIG_SYNC_REQ),
+ MKSTR(SIG_SYNC_RESP),
+ MKSTR(SIG_UDATA),
+ MKSTR(SIG_MDATA),
+ MKSTR(SIG_UPDU_Q),
+ MKSTR(SIG_MPDU_Q),
+ MKSTR(SIG_RETRIEVE),
+};
+
+static const char *const pdus[] = {
+ "illegale PDU type 0", /* no PDU type 0 */
+ MKSTR(PDU_BGN),
+ MKSTR(PDU_BGAK),
+ MKSTR(PDU_END),
+ MKSTR(PDU_ENDAK),
+ MKSTR(PDU_RS),
+ MKSTR(PDU_RSAK),
+ MKSTR(PDU_BGREJ),
+ MKSTR(PDU_SD),
+ MKSTR(PDU_ER),
+ MKSTR(PDU_POLL),
+ MKSTR(PDU_STAT),
+ MKSTR(PDU_USTAT),
+ MKSTR(PDU_UD),
+ MKSTR(PDU_MD),
+ MKSTR(PDU_ERAK),
+};
+#endif
+
+MEMINIT();
+
+static void sscop_signal(struct sscop *, u_int, struct sscop_msg *);
+static void sscop_save_signal(struct sscop *, u_int, struct sscop_msg *);
+static void handle_sigs(struct sscop *);
+static void sscop_set_state(struct sscop *, u_int);
+
+/************************************************************/
+
+
+/************************************************************/
+/*
+ * Queue macros
+ */
+#define SSCOP_MSG_FREE(MSG) \
+ do { \
+ if(MSG) { \
+ MBUF_FREE((MSG)->m); \
+ MSG_FREE((MSG)); \
+ } \
+ } while(0)
+
+
+#define QFIND(Q,RN) \
+ ({ \
+ struct sscop_msg *_msg = NULL, *_m; \
+ MSGQ_FOREACH(_m, (Q)) { \
+ if(_m->seqno == (RN)) { \
+ _msg = _m; \
+ break; \
+ } \
+ } \
+ _msg; \
+ })
+
+#define QINSERT(Q,M) \
+ do { \
+ struct sscop_msg *_msg = NULL, *_m; \
+ MSGQ_FOREACH(_m, (Q)) { \
+ if (_m->seqno > (M)->seqno) { \
+ _msg = _m; \
+ break; \
+ } \
+ } \
+ if (_msg != NULL) \
+ MSGQ_INSERT_BEFORE(_msg, (M)); \
+ else \
+ MSGQ_APPEND((Q), (M)); \
+ } while (0)
+
+
+/*
+ * Send an error indication to the management plane.
+ */
+#define MAAL_ERROR(S,E,C) \
+ do { \
+ VERBOSE(S, SSCOP_DBG_USIG, ((S), (S)->aarg, \
+ "MAA-Signal %s in state %s", \
+ sscop_msigs[SSCOP_MERROR_indication], states[(S)->state])); \
+ (S)->funcs->send_manage((S), (S)->aarg, \
+ SSCOP_MERROR_indication, NULL, (E), (C)); \
+ } while(0)
+
+#define MAAL_DATA(S,M) \
+ do { \
+ VERBOSE(S, SSCOP_DBG_USIG, ((S), (S)->aarg, \
+ "MAA-Signal %s in state %s", \
+ sscop_msigs[SSCOP_MDATA_indication], states[(S)->state])); \
+ (S)->funcs->send_manage((S), (S)->aarg, \
+ SSCOP_MDATA_indication, (M), 0, 0); \
+ } while(0)
+
+#define AAL_DATA(S,D,M,N) \
+ do { \
+ VERBOSE(S, SSCOP_DBG_USIG, ((S), (S)->aarg, \
+ "AA-Signal %s in state %s", \
+ sscop_sigs[D], states[(S)->state])); \
+ (S)->funcs->send_upper((S), (S)->aarg, (D), (M), (N)); \
+ } while(0)
+
+#define AAL_SIG(S,D) \
+ do { \
+ VERBOSE(S, SSCOP_DBG_USIG, ((S), (S)->aarg, \
+ "AA-Signal %s in state %s", \
+ sscop_sigs[D], states[(S)->state])); \
+ (S)->funcs->send_upper((S), (S)->aarg, (D), NULL, 0); \
+ } while(0)
+
+#ifdef SSCOP_DEBUG
+#define AAL_SEND(S,M) do { \
+ if (ISVERBOSE(S, SSCOP_DBG_PDU)) \
+ sscop_dump_pdu(S, "tx", (M)); \
+ (S)->funcs->send_lower((S), (S)->aarg, (M)); \
+ } while(0)
+#else
+#define AAL_SEND(S,M) (S)->funcs->send_lower((S), (S)->aarg, (M))
+#endif
+
+
+/*
+ * Free a save user-to-user data buffer and set the pointer to zero
+ * to signal, that it is free.
+ */
+#define FREE_UU(F) \
+ do { \
+ if(sscop->F) { \
+ MBUF_FREE(sscop->F); \
+ sscop->F = NULL; \
+ } \
+ } while(0)
+
+#define SET_UU(F,U) \
+ do { \
+ FREE_UU(F); \
+ sscop->F = U->m; \
+ U->m = NULL; \
+ SSCOP_MSG_FREE(U); \
+ } while(0)
+
+#define AAL_UU_SIGNAL(S, SIG, M, PL, SN) \
+ do { \
+ if(MBUF_LEN((M)->m) > 0) { \
+ MBUF_UNPAD((M)->m,(PL)); \
+ AAL_DATA((S), (SIG), (M)->m, (SN)); \
+ (M)->m = NULL; \
+ } else { \
+ AAL_DATA((S), (SIG), NULL, (SN)); \
+ } \
+ SSCOP_MSG_FREE((M)); \
+ } while(0)
+
+
+
+TIMER_FUNC(cc, CC)
+TIMER_FUNC(nr, NR)
+TIMER_FUNC(ka, KA)
+TIMER_FUNC(poll, POLL)
+TIMER_FUNC(idle, IDLE)
+
+/************************************************************/
+/*
+ * INSTANCE AND TYPE HANDLING.
+ */
+#ifdef SSCOP_DEBUG
+static void
+sscop_dump_pdu(struct sscop *sscop, const char *dir,
+ const struct SSCOP_MBUF_T *m)
+{
+ u_int32_t v1, v2, v3, v4;
+ u_int size = MBUF_LEN(m);
+ u_int n, i;
+
+ if (size < 8)
+ return;
+
+ v1 = MBUF_TRAIL32(m, -1);
+ v2 = MBUF_TRAIL32(m, -2);
+
+ switch ((v1 >> 24) & 0xf) {
+
+ case 0:
+ return;
+
+ case PDU_BGN:
+ sscop->funcs->verbose(sscop, sscop->aarg,
+ "%s BGN n(mr)=%u n(sq)=%u pl=%u",
+ dir, v1 & 0xffffff, v2 & 0xff, (v1 >> 30) & 0x3);
+ return;
+
+ case PDU_BGAK:
+ sscop->funcs->verbose(sscop, sscop->aarg,
+ "%s BGAK n(mr)=%u pl=%u",
+ dir, v1 & 0xffffff, (v1 >> 30) & 0x3);
+ return;
+
+ case PDU_END:
+ sscop->funcs->verbose(sscop, sscop->aarg,
+ "%s END r=%u s=%u pl=%u",
+ dir, (v1 >> 29) & 1, (v1 >> 28) & 1, (v1 >> 30) & 0x3);
+ return;
+
+ case PDU_ENDAK:
+ sscop->funcs->verbose(sscop, sscop->aarg, "%s ENDAK", dir);
+ return;
+
+ case PDU_RS:
+ sscop->funcs->verbose(sscop, sscop->aarg,
+ "%s RS n(mr)=%u n(sq)=%u pl=%u",
+ dir, v1 & 0xffffff, v2 & 0xff, (v1 >> 30) & 0x3);
+ return;
+
+ case PDU_RSAK:
+ sscop->funcs->verbose(sscop, sscop->aarg, "%s RSAK n(mr)=%u",
+ dir, v1 & 0xffffff);
+ return;
+
+ case PDU_BGREJ:
+ sscop->funcs->verbose(sscop, sscop->aarg, "%s BGREJ pl=%u",
+ dir, (v1 >> 30) & 0x3);
+ return;
+
+ case PDU_SD:
+ sscop->funcs->verbose(sscop, sscop->aarg, "%s SD n(s)=%u pl=%u",
+ dir, v1 & 0xffffff, (v1 >> 30) & 0x3);
+ return;
+
+ case PDU_ER:
+ sscop->funcs->verbose(sscop, sscop->aarg, "%s ER n(mr)=%u n(sq)=%u",
+ dir, v1 & 0xffffff, v2 & 0xff);
+ return;
+
+ case PDU_POLL:
+ sscop->funcs->verbose(sscop, sscop->aarg, "%s POLL n(s)=%u n(ps)=%u",
+ dir, v1 & 0xffffff, v2 & 0xffffff);
+ return;
+
+ case PDU_STAT:
+ if (size < 12)
+ return;
+ v3 = MBUF_TRAIL32(m, -3);
+ sscop->funcs->verbose(sscop, sscop->aarg,
+ "%s STAT n(r)=%u n(mr)=%u n(ps)=%u",
+ dir, v1 & 0xffffff, v2 & 0xffffff, v3 & 0xffffff);
+ n = (size - 12) / 4;
+ for (i = 0; i < (size - 12) / 4; i++, n--) {
+ v4 = MBUF_TRAIL32(m, -4 - (int)i);
+ sscop->funcs->verbose(sscop, sscop->aarg,
+ " LE(%u)=%u", n, v4 & 0xffffff);
+ }
+ return;
+
+ case PDU_USTAT:
+ if (size < 16)
+ return;
+ sscop->funcs->verbose(sscop, sscop->aarg,
+ "%s STAT n(r)=%u n(mr)=%u LE1=%u LE2=%u",
+ dir, v1 & 0xffffff, v2 & 0xffffff,
+ MBUF_TRAIL32(m, -4) & 0xffffff,
+ MBUF_TRAIL32(m, -3) & 0xffffff);
+ return;
+
+ case PDU_UD:
+ sscop->funcs->verbose(sscop, sscop->aarg,
+ "%s UD pl=%u", dir, (v1 >> 30) & 0x3);
+ return;
+
+ case PDU_MD:
+ sscop->funcs->verbose(sscop, sscop->aarg,
+ "%s MD pl=%u", dir, (v1 >> 30) & 0x3);
+ return;
+
+ case PDU_ERAK:
+ sscop->funcs->verbose(sscop, sscop->aarg,
+ "%s ERAK n(mr)=%u", dir, v1 & 0xffffff);
+ return;
+ }
+}
+#endif
+
+
+/*
+ * Initialize state of variables
+ */
+static void
+sscop_init(struct sscop *sscop)
+{
+ sscop->state = SSCOP_IDLE;
+
+ sscop->vt_sq = 0;
+ sscop->vr_sq = 0;
+ sscop->clear_buffers = 1;
+
+ sscop->ll_busy = 0;
+
+ sscop->rxq = 0;
+}
+
+static void
+sscop_clear(struct sscop *sscop)
+{
+ TIMER_STOP(sscop, cc);
+ TIMER_STOP(sscop, ka);
+ TIMER_STOP(sscop, nr);
+ TIMER_STOP(sscop, idle);
+ TIMER_STOP(sscop, poll);
+
+ FREE_UU(uu_bgn);
+ FREE_UU(uu_bgak);
+ FREE_UU(uu_bgrej);
+ FREE_UU(uu_end);
+ FREE_UU(uu_rs);
+
+ MSGQ_CLEAR(&sscop->xq);
+ MSGQ_CLEAR(&sscop->uxq);
+ MSGQ_CLEAR(&sscop->mxq);
+ MSGQ_CLEAR(&sscop->xbuf);
+ MSGQ_CLEAR(&sscop->rbuf);
+
+ SIGQ_CLEAR(&sscop->sigs);
+ SIGQ_CLEAR(&sscop->saved_sigs);
+}
+
+
+/*
+ * Allocate instance memory, initialize the state of all variables.
+ */
+struct sscop *
+sscop_create(void *a, const struct sscop_funcs *funcs)
+{
+ struct sscop *sscop;
+
+ MEMZALLOC(sscop, struct sscop *, sizeof(struct sscop));
+ if (sscop == NULL)
+ return (NULL);
+
+ if (a == NULL)
+ sscop->aarg = sscop;
+ else
+ sscop->aarg = a;
+ sscop->funcs = funcs;
+
+ sscop->maxk = MAXK;
+ sscop->maxj = MAXJ;
+ sscop->maxcc = MAXCC;
+ sscop->maxpd = MAXPD;
+ sscop->maxstat = MAXSTAT;
+ sscop->timercc = TIMERCC;
+ sscop->timerka = TIMERKA;
+ sscop->timernr = TIMERNR;
+ sscop->timerpoll = TIMERPOLL;
+ sscop->timeridle = TIMERIDLE;
+ sscop->robustness = 0;
+ sscop->poll_after_rex = 0;
+ sscop->mr = MAXMR;
+
+ TIMER_INIT(sscop, cc);
+ TIMER_INIT(sscop, nr);
+ TIMER_INIT(sscop, ka);
+ TIMER_INIT(sscop, poll);
+ TIMER_INIT(sscop, idle);
+
+ MSGQ_INIT(&sscop->xq);
+ MSGQ_INIT(&sscop->uxq);
+ MSGQ_INIT(&sscop->mxq);
+ MSGQ_INIT(&sscop->rbuf);
+ MSGQ_INIT(&sscop->xbuf);
+
+ SIGQ_INIT(&sscop->sigs);
+ SIGQ_INIT(&sscop->saved_sigs);
+
+ sscop_init(sscop);
+
+ return (sscop);
+}
+
+/*
+ * Free all resources in a sscop instance
+ */
+void
+sscop_destroy(struct sscop *sscop)
+{
+ sscop_reset(sscop);
+
+ MEMFREE(sscop);
+}
+
+/*
+ * Reset the SSCOP instance.
+ */
+void
+sscop_reset(struct sscop *sscop)
+{
+ sscop_clear(sscop);
+ sscop_init(sscop);
+}
+
+void
+sscop_getparam(const struct sscop *sscop, struct sscop_param *p)
+{
+ p->timer_cc = sscop->timercc;
+ p->timer_poll = sscop->timerpoll;
+ p->timer_keep_alive = sscop->timerka;
+ p->timer_no_response = sscop->timernr;
+ p->timer_idle = sscop->timeridle;
+ p->maxk = sscop->maxk;
+ p->maxj = sscop->maxj;
+ p->maxcc = sscop->maxcc;
+ p->maxpd = sscop->maxpd;
+ p->maxstat = sscop->maxstat;
+ p->mr = sscop->mr;
+ p->flags = 0;
+ if(sscop->robustness)
+ p->flags |= SSCOP_ROBUST;
+ if(sscop->poll_after_rex)
+ p->flags |= SSCOP_POLLREX;
+}
+
+int
+sscop_setparam(struct sscop *sscop, struct sscop_param *p, u_int *pmask)
+{
+ u_int mask = *pmask;
+
+ /* can change only in idle state */
+ if (sscop->state != SSCOP_IDLE)
+ return (EISCONN);
+
+ *pmask = 0;
+
+ /*
+ * first check all parameters
+ */
+ if ((mask & SSCOP_SET_TCC) && p->timer_cc == 0)
+ *pmask |= SSCOP_SET_TCC;
+ if ((mask & SSCOP_SET_TPOLL) && p->timer_poll == 0)
+ *pmask |= SSCOP_SET_TPOLL;
+ if ((mask & SSCOP_SET_TKA) && p->timer_keep_alive == 0)
+ *pmask |= SSCOP_SET_TKA;
+ if ((mask & SSCOP_SET_TNR) && p->timer_no_response == 0)
+ *pmask |= SSCOP_SET_TNR;
+ if ((mask & SSCOP_SET_TIDLE) && p->timer_idle == 0)
+ *pmask |= SSCOP_SET_TIDLE;
+ if ((mask & SSCOP_SET_MAXK) && p->maxk > MAXMAXK)
+ *pmask |= SSCOP_SET_MAXK;
+ if ((mask & SSCOP_SET_MAXJ) && p->maxj > MAXMAXJ)
+ *pmask |= SSCOP_SET_MAXJ;
+ if ((mask & SSCOP_SET_MAXCC) && p->maxcc > 255)
+ *pmask |= SSCOP_SET_MAXCC;
+ if ((mask & SSCOP_SET_MAXPD) && p->maxpd >= (1 << 24))
+ *pmask |= SSCOP_SET_MAXPD;
+ if ((mask & SSCOP_SET_MAXSTAT) &&
+ ((p->maxstat & 1) == 0 || p->maxstat == 1 || p->maxstat == 2 ||
+ p->maxstat * 4 > MAXMAXK - 8))
+ *pmask |= SSCOP_SET_MAXSTAT;
+ if ((mask & SSCOP_SET_MR) && p->mr >= (1 << 24) - 1)
+ *pmask |= SSCOP_SET_MR;
+
+ if (*pmask)
+ return (EINVAL);
+
+
+ /*
+ * now set it
+ */
+ if (mask & SSCOP_SET_TCC)
+ sscop->timercc = p->timer_cc;
+
+ if (mask & SSCOP_SET_TPOLL)
+ sscop->timerpoll = p->timer_poll;
+
+ if (mask & SSCOP_SET_TKA)
+ sscop->timerka = p->timer_keep_alive;
+
+ if (mask & SSCOP_SET_TNR)
+ sscop->timernr = p->timer_no_response;
+
+ if (mask & SSCOP_SET_TIDLE)
+ sscop->timeridle = p->timer_idle;
+
+ if (mask & SSCOP_SET_MAXK)
+ sscop->maxk = p->maxk;
+ if (mask & SSCOP_SET_MAXJ)
+ sscop->maxj = p->maxj;
+
+ if (mask & SSCOP_SET_MAXCC)
+ sscop->maxcc = p->maxcc;
+ if (mask & SSCOP_SET_MAXPD)
+ sscop->maxpd = p->maxpd;
+ if (mask & SSCOP_SET_MAXSTAT)
+ sscop->maxstat = p->maxstat;
+
+ if (mask & SSCOP_SET_MR)
+ sscop->mr = p->mr;
+
+ if (mask & SSCOP_SET_ROBUST)
+ sscop->robustness = ((p->flags & SSCOP_ROBUST) != 0);
+
+ if (mask & SSCOP_SET_POLLREX)
+ sscop->poll_after_rex = ((p->flags & SSCOP_POLLREX) != 0);
+
+ return (0);
+}
+
+enum sscop_state
+sscop_getstate(const struct sscop *sscop)
+{
+ return (sscop->state);
+}
+
+
+/************************************************************/
+/*
+ * EXTERNAL INPUT SIGNAL MAPPING
+ */
+
+/*
+ * Map AA signal to SSCOP internal signal
+ */
+int
+sscop_aasig(struct sscop *sscop, enum sscop_aasig sig,
+ struct SSCOP_MBUF_T *m, u_int arg)
+{
+ struct sscop_msg *msg;
+
+ if (sig >= sizeof(sscop_sigs)/sizeof(sscop_sigs[0])) {
+ VERBOSE(sscop, SSCOP_DBG_INSIG, (sscop, sscop->aarg,
+ "AA-Signal %u - bad signal", sig));
+ MBUF_FREE(m);
+ return (EINVAL);
+ }
+ VERBOSE(sscop, SSCOP_DBG_INSIG, (sscop, sscop->aarg,
+ "AA-Signal %s in state %s with%s message",
+ sscop_sigs[sig], states[sscop->state], m ? "" : "out"));
+
+ MSG_ALLOC(msg);
+ if (msg == NULL) {
+ FAILURE("sscop: cannot allocate aasig");
+ MBUF_FREE(m);
+ return (ENOMEM);
+ }
+
+ switch(sig) {
+
+ case SSCOP_ESTABLISH_request:
+ msg->m = m;
+ msg->rexmit = arg;
+ sscop_signal(sscop, SIG_ESTAB_REQ, msg);
+ break;
+
+ case SSCOP_ESTABLISH_response:
+ msg->m = m;
+ msg->rexmit = arg;
+ sscop_signal(sscop, SIG_ESTAB_RESP, msg);
+ break;
+
+ case SSCOP_RELEASE_request:
+ msg->m = m;
+ sscop_signal(sscop, SIG_RELEASE_REQ, msg);
+ break;
+
+ case SSCOP_DATA_request:
+ msg->m = m;
+ sscop_signal(sscop, SIG_USER_DATA, msg);
+ break;
+
+ case SSCOP_UDATA_request:
+ msg->m = m;
+ sscop_signal(sscop, SIG_UDATA, msg);
+ break;
+
+ case SSCOP_RECOVER_response:
+ MBUF_FREE(m);
+ MSG_FREE(msg);
+ sscop_signal(sscop, SIG_RECOVER, NULL);
+ break;
+
+ case SSCOP_RESYNC_request:
+ msg->m = m;
+ sscop_signal(sscop, SIG_SYNC_REQ, msg);
+ break;
+
+ case SSCOP_RESYNC_response:
+ MBUF_FREE(m);
+ MSG_FREE(msg);
+ sscop_signal(sscop, SIG_SYNC_RESP, NULL);
+ break;
+
+ case SSCOP_RETRIEVE_request:
+ MBUF_FREE(m);
+ msg->rexmit = arg;
+ sscop_signal(sscop, SIG_RETRIEVE, msg);
+ break;
+
+ case SSCOP_ESTABLISH_indication:
+ case SSCOP_ESTABLISH_confirm:
+ case SSCOP_RELEASE_indication:
+ case SSCOP_RELEASE_confirm:
+ case SSCOP_DATA_indication:
+ case SSCOP_UDATA_indication:
+ case SSCOP_RECOVER_indication:
+ case SSCOP_RESYNC_indication:
+ case SSCOP_RESYNC_confirm:
+ case SSCOP_RETRIEVE_indication:
+ case SSCOP_RETRIEVE_COMPL_indication:
+ MBUF_FREE(m);
+ MSG_FREE(msg);
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Signal from layer management.
+ */
+int
+sscop_maasig(struct sscop *sscop, enum sscop_maasig sig, struct SSCOP_MBUF_T *m)
+{
+ struct sscop_msg *msg;
+
+ if (sig >= sizeof(sscop_msigs)/sizeof(sscop_msigs[0])) {
+ VERBOSE(sscop, SSCOP_DBG_INSIG, (sscop, sscop->aarg,
+ "MAA-Signal %u - bad signal", sig));
+ MBUF_FREE(m);
+ return (EINVAL);
+ }
+ VERBOSE(sscop, SSCOP_DBG_INSIG, (sscop, sscop->aarg,
+ "MAA-Signal %s in state %s with%s message",
+ sscop_msigs[sig], states[sscop->state], m ? "" : "out"));
+
+ MSG_ALLOC(msg);
+ if (msg == NULL) {
+ FAILURE("sscop: cannot allocate maasig");
+ MBUF_FREE(m);
+ return (ENOMEM);
+ }
+
+ switch (sig) {
+
+ case SSCOP_MDATA_request:
+ msg->m = m;
+ sscop_signal(sscop, SIG_MDATA, msg);
+ break;
+
+ case SSCOP_MDATA_indication:
+ case SSCOP_MERROR_indication:
+ MBUF_FREE(m);
+ MSG_FREE(msg);
+ return (EINVAL);
+ }
+ return (0);
+}
+
+/*
+ * Map PDU to SSCOP signal.
+ */
+void
+sscop_input(struct sscop *sscop, struct SSCOP_MBUF_T *m)
+{
+ struct sscop_msg *msg;
+ union pdu pdu;
+ u_int size;
+
+ MSG_ALLOC(msg);
+ if(msg == NULL) {
+ FAILURE("sscop: cannot allocate in pdu msg");
+ MBUF_FREE(m);
+ return;
+ }
+
+ msg->m = m;
+ msg->rexmit = 0;
+
+ size = MBUF_LEN(m);
+
+ if(size % 4 != 0 || size < 4)
+ goto err;
+
+ pdu.sscop_null = MBUF_TRAIL32(m, -1);
+
+ VERBOSE(sscop, SSCOP_DBG_PDU, (sscop, sscop->aarg,
+ "got %s, size=%u", pdus[pdu.sscop_type], size));
+
+#ifdef SSCOP_DEBUG
+#define ENSURE(C,F) if(!(C)) { VERBOSE(sscop, SSCOP_DBG_PDU, F); goto err; }
+#else
+#define ENSURE(C,F) if(!(C)) goto err
+#endif
+
+#ifdef SSCOP_DEBUG
+ if (ISVERBOSE(sscop, SSCOP_DBG_PDU))
+ sscop_dump_pdu(sscop, "rx", m);
+#endif
+
+ switch(pdu.sscop_type) {
+
+ default:
+ ENSURE(0, (sscop, sscop->aarg,
+ "Bad PDU type %u", pdu.sscop_type));
+ break;
+
+ case PDU_BGN:
+ ENSURE(size >= 8U, (sscop, sscop->aarg,
+ "PDU_BGN size=%u", size));
+ ENSURE(size >= 8U + pdu.sscop_pl, (sscop, sscop->aarg,
+ "PDU_BGN size=%u pl=%u", size, pdu.sscop_pl));
+ ENSURE(size <= 8U + sscop->maxj, (sscop, sscop->aarg,
+ "PDU_BGN size=%u", size));
+ sscop_signal(sscop, SIG_BGN, msg);
+ break;
+
+ case PDU_BGAK:
+ ENSURE(size >= 8U, (sscop, sscop->aarg,
+ "PDU_BGAK size=%u", size));
+ ENSURE(size >= 8U + pdu.sscop_pl, (sscop, sscop->aarg,
+ "PDU_BGAK size=%u pl=%u", size, pdu.sscop_pl));
+ ENSURE(size <= 8U + sscop->maxj, (sscop, sscop->aarg,
+ "PDU_BGAK size=%u", size));
+ sscop_signal(sscop, SIG_BGAK, msg);
+ break;
+
+ case PDU_END:
+ ENSURE(size >= 8U, (sscop, sscop->aarg,
+ "PDU_END size=%u", size));
+ ENSURE(size >= 8U + pdu.sscop_pl, (sscop, sscop->aarg,
+ "PDU_END size=%u pl=%u", size, pdu.sscop_pl));
+ ENSURE(size <= 8U + sscop->maxj, (sscop, sscop->aarg,
+ "PDU_END size=%u", size));
+ sscop_signal(sscop, SIG_END, msg);
+ break;
+
+ case PDU_ENDAK:
+ ENSURE(size == 8U, (sscop, sscop->aarg,
+ "PDU_ENDAK size=%u", size));
+ sscop_signal(sscop, SIG_ENDAK, msg);
+ break;
+
+ case PDU_BGREJ:
+ ENSURE(size >= 8U, (sscop, sscop->aarg,
+ "PDU_BGREJ size=%u", size));
+ ENSURE(size >= 8U + pdu.sscop_pl, (sscop, sscop->aarg,
+ "PDU_BGREJ size=%u pl=%u", size, pdu.sscop_pl));
+ ENSURE(size <= 8U + sscop->maxj, (sscop, sscop->aarg,
+ "PDU_BGREJ size=%u", size));
+ sscop_signal(sscop, SIG_BGREJ, msg);
+ break;
+
+ case PDU_SD:
+ ENSURE(size >= 4U + pdu.sscop_pl, (sscop, sscop->aarg,
+ "PDU_SD size=%u pl=%u", size, pdu.sscop_pl));
+ ENSURE(size <= 4U + sscop->maxk, (sscop, sscop->aarg,
+ "PDU_SD size=%u", size));
+ sscop_signal(sscop, SIG_SD, msg);
+ break;
+
+ case PDU_UD:
+ ENSURE(size >= 4U + pdu.sscop_pl, (sscop, sscop->aarg,
+ "PDU_UD size=%u pl=%u", size, pdu.sscop_pl));
+ ENSURE(size <= 4U + sscop->maxk, (sscop, sscop->aarg,
+ "PDU_UD size=%u", size));
+ sscop_signal(sscop, SIG_UD, msg);
+ break;
+
+ case PDU_MD:
+ ENSURE(size >= 4U + pdu.sscop_pl, (sscop, sscop->aarg,
+ "PDU_MD size=%u pl=%u", size, pdu.sscop_pl));
+ ENSURE(size <= 4U + sscop->maxk, (sscop, sscop->aarg,
+ "PDU_MD size=%u", size));
+ sscop_signal(sscop, SIG_MD, msg);
+ break;
+
+ case PDU_POLL:
+ ENSURE(size == 8U, (sscop, sscop->aarg,
+ "PDU_POLL size=%u", size));
+ sscop_signal(sscop, SIG_POLL, msg);
+ break;
+
+ case PDU_STAT:
+ ENSURE(size >= 12U, (sscop, sscop->aarg,
+ "PDU_STAT size=%u", size));
+ ENSURE(size <= 12U + 4 * sscop->maxstat, (sscop, sscop->aarg,
+ "PDU_STAT size=%u", size));
+ sscop_signal(sscop, SIG_STAT, msg);
+ break;
+
+ case PDU_RS:
+ ENSURE(size >= 8U, (sscop, sscop->aarg,
+ "PDU_RS size=%u", size));
+ ENSURE(size >= 8U + pdu.sscop_pl, (sscop, sscop->aarg,
+ "PDU_RS size=%u pl=%u", size, pdu.sscop_pl));
+ ENSURE(size <= 8U + sscop->maxj, (sscop, sscop->aarg,
+ "PDU_RS size=%u", size));
+ sscop_signal(sscop, SIG_RS, msg);
+ break;
+
+ case PDU_RSAK:
+ ENSURE(size == 8U, (sscop, sscop->aarg,
+ "PDU_RSAK size=%u", size));
+ sscop_signal(sscop, SIG_RSAK, msg);
+ break;
+
+ case PDU_ER:
+ ENSURE(size == 8U, (sscop, sscop->aarg,
+ "PDU_ER size=%u", size));
+ sscop_signal(sscop, SIG_ER, msg);
+ break;
+
+ case PDU_ERAK:
+ ENSURE(size == 8U, (sscop, sscop->aarg,
+ "PDU_ERAK size=%u", size));
+ sscop_signal(sscop, SIG_ERAK, msg);
+ break;
+
+ case PDU_USTAT:
+ ENSURE(size == 16U, (sscop, sscop->aarg,
+ "PDU_ERAK size=%u", size));
+ sscop_signal(sscop, SIG_USTAT, msg);
+ break;
+ }
+#undef ENSURE
+ return;
+
+ err:
+ MAAL_ERROR(sscop, 'U', 0);
+ SSCOP_MSG_FREE(msg);
+}
+
+/************************************************************/
+/*
+ * UTILITIES
+ */
+
+/*
+ * Move the receiver window by N packets
+ */
+u_int
+sscop_window(struct sscop *sscop, u_int n)
+{
+ sscop->vr_mr += n;
+ return (SEQNO_DIFF(sscop->vr_mr, sscop->vr_r));
+}
+
+/*
+ * Lower layer busy handling
+ */
+u_int
+sscop_setbusy(struct sscop *sscop, int busy)
+{
+ u_int old = sscop->ll_busy;
+
+ if (busy > 0)
+ sscop->ll_busy = 1;
+ else if (busy == 0) {
+ sscop->ll_busy = 0;
+ if(old)
+ handle_sigs(sscop);
+ }
+
+ return (old);
+}
+
+const char *
+sscop_signame(enum sscop_aasig sig)
+{
+ static char str[40];
+
+ if (sig >= sizeof(sscop_sigs)/sizeof(sscop_sigs[0])) {
+ sprintf(str, "BAD SSCOP_AASIG %u", sig);
+ return (str);
+ } else {
+ return (sscop_sigs[sig]);
+ }
+}
+
+const char *
+sscop_msigname(enum sscop_maasig sig)
+{
+ static char str[40];
+
+ if (sig >= sizeof(sscop_msigs)/sizeof(sscop_msigs[0])) {
+ sprintf(str, "BAD SSCOP_MAASIG %u", sig);
+ return (str);
+ } else {
+ return (sscop_msigs[sig]);
+ }
+}
+
+const char *
+sscop_statename(enum sscop_state s)
+{
+ static char str[40];
+
+ if (s >= sizeof(states)/sizeof(states[0])) {
+ sprintf(str, "BAD SSCOP_STATE %u", s);
+ return (str);
+ } else {
+ return (states[s]);
+ }
+}
+
+
+/************************************************************/
+/*
+ * MACROS
+ */
+
+/*
+ * p 75: release buffers
+ */
+static void
+m_release_buffers(struct sscop *sscop)
+{
+ MSGQ_CLEAR(&sscop->xq);
+ MSGQ_CLEAR(&sscop->xbuf);
+ sscop->rxq = 0;
+ MSGQ_CLEAR(&sscop->rbuf);
+}
+
+/*
+ * P 75: Prepare retrival
+ */
+static void
+m_prepare_retrieval(struct sscop *sscop)
+{
+ struct sscop_msg *msg;
+
+ if (sscop->clear_buffers) {
+ MSGQ_CLEAR(&sscop->xq);
+ MSGQ_CLEAR(&sscop->xbuf);
+ }
+ MSGQ_FOREACH(msg, &sscop->xbuf)
+ msg->rexmit = 0;
+ sscop->rxq = 0;
+
+ MSGQ_CLEAR(&sscop->rbuf);
+}
+
+/*
+ * P 75: Prepare retrival
+ */
+static void
+m_prepare_recovery(struct sscop *sscop)
+{
+ struct sscop_msg *msg;
+
+ if(sscop->clear_buffers) {
+ MSGQ_CLEAR(&sscop->xq);
+ MSGQ_CLEAR(&sscop->xbuf);
+ }
+ MSGQ_FOREACH(msg, &sscop->xbuf)
+ msg->rexmit = 0;
+ sscop->rxq = 0;
+}
+
+
+/*
+ * P 75: Clear transmitter
+ */
+static void
+m_clear_transmitter(struct sscop *sscop)
+{
+ if(!sscop->clear_buffers) {
+ MSGQ_CLEAR(&sscop->xq);
+ MSGQ_CLEAR(&sscop->xbuf);
+ }
+}
+
+
+/*
+ * p 75: Deliver data
+ * Freeing the message is the responibility of the handler function.
+ */
+static void
+m_deliver_data(struct sscop *sscop)
+{
+ struct sscop_msg *msg;
+ u_int sn;
+
+ if ((msg = MSGQ_GET(&sscop->rbuf)) == NULL)
+ return;
+
+ if (sscop->clear_buffers) {
+ MSGQ_CLEAR(&sscop->rbuf);
+ return;
+ }
+
+ sn = msg->seqno + 1;
+ AAL_DATA(sscop, SSCOP_DATA_indication, msg->m, msg->seqno);
+ MSG_FREE(msg);
+
+ while ((msg = MSGQ_GET(&sscop->rbuf)) != NULL) {
+ ASSERT(msg->seqno == sn);
+ if (++sn == SSCOP_MAXSEQNO)
+ sn = 0;
+ AAL_DATA(sscop, SSCOP_DATA_indication, msg->m, msg->seqno);
+ MSG_FREE(msg);
+ }
+}
+
+/*
+ * P 75: Initialize state variables
+ */
+static void
+m_initialize_state(struct sscop *sscop)
+{
+ sscop->vt_s = 0;
+ sscop->vt_ps = 0;
+ sscop->vt_a = 0;
+
+ sscop->vt_pa = 1;
+ sscop->vt_pd = 0;
+ sscop->credit = 1;
+
+ sscop->vr_r = 0;
+ sscop->vr_h = 0;
+}
+
+/*
+ * p 76: Data retrieval
+ */
+static void
+m_data_retrieval(struct sscop *sscop, u_int rn)
+{
+ struct sscop_msg *s;
+
+ if (rn != SSCOP_RETRIEVE_UNKNOWN) {
+ if(rn >= SSCOP_RETRIEVE_TOTAL)
+ rn = sscop->vt_a;
+ else
+ rn++;
+ while(rn >= sscop->vt_a && rn < sscop->vt_s) {
+ if(rn == SSCOP_MAXSEQNO) rn = 0;
+ if((s = QFIND(&sscop->xbuf, rn)) != NULL) {
+ MSGQ_REMOVE(&sscop->xbuf, s);
+ AAL_DATA(sscop, SSCOP_RETRIEVE_indication,
+ s->m, 0);
+ MSG_FREE(s);
+ }
+ rn++;
+ }
+ }
+
+ while((s = MSGQ_GET(&sscop->xq)) != NULL) {
+ AAL_DATA(sscop, SSCOP_RETRIEVE_indication, s->m, 0);
+ MSG_FREE(s);
+ }
+ AAL_SIG(sscop, SSCOP_RETRIEVE_COMPL_indication);
+}
+
+/*
+ * P 76: Detect retransmission. PDU type must already be stripped.
+ */
+static int
+m_detect_retransmission(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union bgn bgn;
+
+ bgn.sscop_null = MBUF_TRAIL32(msg->m, -1);
+
+ if (sscop->vr_sq == bgn.sscop_bgns)
+ return (1);
+
+ sscop->vr_sq = bgn.sscop_bgns;
+ return (0);
+}
+
+/*
+ * P 76: Set POLL timer
+ */
+static void
+m_set_poll_timer(struct sscop *sscop)
+{
+ if(MSGQ_EMPTY(&sscop->xq) && sscop->vt_s == sscop->vt_a)
+ TIMER_RESTART(sscop, ka);
+ else
+ TIMER_RESTART(sscop, poll);
+}
+
+/*
+ * P 77: Reset data transfer timers
+ */
+static void
+m_reset_data_xfer_timers(struct sscop *sscop)
+{
+ TIMER_STOP(sscop, ka);
+ TIMER_STOP(sscop, nr);
+ TIMER_STOP(sscop, idle);
+ TIMER_STOP(sscop, poll);
+}
+
+/*
+ * P 77: Set data transfer timers
+ */
+static void
+m_set_data_xfer_timers(struct sscop *sscop)
+{
+ TIMER_RESTART(sscop, poll);
+ TIMER_RESTART(sscop, nr);
+}
+
+/*
+ * P 77: Initialize VR(MR)
+ */
+static void
+m_initialize_mr(struct sscop *sscop)
+{
+ sscop->vr_mr = sscop->mr;
+}
+
+/************************************************************/
+/*
+ * CONDITIONS
+ */
+static int
+c_ready_pduq(struct sscop *sscop)
+{
+ if (!sscop->ll_busy &&
+ (sscop->rxq != 0 ||
+ sscop->vt_s < sscop->vt_ms ||
+ TIMER_ISACT(sscop, idle)))
+ return (1);
+ return (0);
+}
+
+/************************************************************/
+/*
+ * SEND PDUS
+ */
+
+/*
+ * Send BG PDU.
+ */
+static void
+send_bgn(struct sscop *sscop, struct SSCOP_MBUF_T *uu)
+{
+ union pdu pdu;
+ union bgn bgn;
+ struct SSCOP_MBUF_T *m;
+
+ pdu.sscop_null = 0;
+ pdu.sscop_type = PDU_BGN;
+ pdu.sscop_ns = sscop->vr_mr;
+
+ bgn.sscop_null = 0;
+ bgn.sscop_bgns = sscop->vt_sq;
+
+ if(uu) {
+ if ((m = MBUF_DUP(uu)) == NULL) {
+ FAILURE("sscop: cannot allocate BGN");
+ return;
+ }
+ pdu.sscop_pl += MBUF_PAD4(m);
+ } else {
+ if ((m = MBUF_ALLOC(8)) == NULL) {
+ FAILURE("sscop: cannot allocate BGN");
+ return;
+ }
+ }
+
+ MBUF_APPEND32(m, bgn.sscop_null);
+ MBUF_APPEND32(m, pdu.sscop_null);
+
+ AAL_SEND(sscop, m);
+}
+
+/*
+ * Send BGREJ PDU.
+ */
+static void
+send_bgrej(struct sscop *sscop, struct SSCOP_MBUF_T *uu)
+{
+ union pdu pdu;
+ union bgn bgn;
+ struct SSCOP_MBUF_T *m;
+
+ pdu.sscop_null = 0;
+ pdu.sscop_type = PDU_BGREJ;
+ bgn.sscop_null = 0;
+
+ if(uu) {
+ if((m = MBUF_DUP(uu)) == NULL) {
+ FAILURE("sscop: cannot allocate BGREJ");
+ return;
+ }
+ pdu.sscop_pl += MBUF_PAD4(m);
+ } else {
+ if((m = MBUF_ALLOC(8)) == NULL) {
+ FAILURE("sscop: cannot allocate BGREJ");
+ return;
+ }
+ }
+
+ MBUF_APPEND32(m, bgn.sscop_null);
+ MBUF_APPEND32(m, pdu.sscop_null);
+
+ AAL_SEND(sscop, m);
+}
+
+/*
+ * Send BGAK PDU.
+ */
+static void
+send_bgak(struct sscop *sscop, struct SSCOP_MBUF_T *uu)
+{
+ union pdu pdu;
+ union bgn bgn;
+ struct SSCOP_MBUF_T *m;
+
+ pdu.sscop_null = 0;
+ pdu.sscop_type = PDU_BGAK;
+ pdu.sscop_ns = sscop->vr_mr;
+ bgn.sscop_null = 0;
+
+ if(uu) {
+ if((m = MBUF_DUP(uu)) == NULL) {
+ FAILURE("sscop: cannot allocate BGAK");
+ return;
+ }
+ pdu.sscop_pl += MBUF_PAD4(m);
+ } else {
+ if((m = MBUF_ALLOC(8)) == NULL) {
+ FAILURE("sscop: cannot allocate BGAK");
+ return;
+ }
+ }
+
+ MBUF_APPEND32(m, bgn.sscop_null);
+ MBUF_APPEND32(m, pdu.sscop_null);
+
+ AAL_SEND(sscop, m);
+}
+
+/*
+ * Send SD PDU. The function makes a duplicate of the message.
+ */
+static void
+send_sd(struct sscop *sscop, struct SSCOP_MBUF_T *m, u_int seqno)
+{
+ union pdu pdu;
+
+ if((m = MBUF_DUP(m)) == NULL) {
+ FAILURE("sscop: cannot allocate SD");
+ return;
+ }
+
+ pdu.sscop_null = 0;
+ pdu.sscop_pl = 0;
+ pdu.sscop_type = PDU_SD;
+ pdu.sscop_ns = seqno;
+
+ pdu.sscop_pl += MBUF_PAD4(m);
+
+ MBUF_APPEND32(m, pdu.sscop_null);
+
+ AAL_SEND(sscop, m);
+}
+
+/*
+ * Send a UD PDU. The caller must free the sscop msg part.
+ */
+static void
+send_ud(struct sscop *sscop, struct SSCOP_MBUF_T *m)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = 0;
+ pdu.sscop_type = PDU_UD;
+
+ pdu.sscop_pl += MBUF_PAD4(m);
+
+ MBUF_APPEND32(m, pdu.sscop_null);
+
+ AAL_SEND(sscop, m);
+}
+
+/*
+ * Send a MD PDU. The caller must free the sscop msg part.
+ */
+static void
+send_md(struct sscop *sscop, struct SSCOP_MBUF_T *m)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = 0;
+ pdu.sscop_type = PDU_MD;
+
+ pdu.sscop_pl += MBUF_PAD4(m);
+
+ MBUF_APPEND32(m, pdu.sscop_null);
+
+ AAL_SEND(sscop, m);
+}
+
+/*
+ * Send END PDU.
+ */
+static void
+send_end(struct sscop *sscop, int src, struct SSCOP_MBUF_T *uu)
+{
+ union pdu pdu;
+ struct SSCOP_MBUF_T *m;
+
+ sscop->last_end_src = src;
+
+ pdu.sscop_null = 0;
+ pdu.sscop_s = src;
+ pdu.sscop_type = PDU_END;
+
+ if(uu) {
+ if((m = MBUF_DUP(uu)) == NULL) {
+ FAILURE("sscop: cannot allocate END");
+ return;
+ }
+ pdu.sscop_pl += MBUF_PAD4(m);
+ } else {
+ if((m = MBUF_ALLOC(8)) == NULL) {
+ FAILURE("sscop: cannot allocate END");
+ return;
+ }
+ }
+
+ MBUF_APPEND32(m, 0);
+ MBUF_APPEND32(m, pdu.sscop_null);
+
+ AAL_SEND(sscop, m);
+}
+
+/*
+ * Send USTAT PDU. List must be terminated by -1.
+ */
+static void
+send_ustat(struct sscop *sscop, ...)
+{
+ va_list ap;
+ int f;
+ u_int n;
+ union pdu pdu;
+ union seqno seqno;
+ struct SSCOP_MBUF_T *m;
+
+ va_start(ap, sscop);
+ n = 0;
+ while((f = va_arg(ap, int)) >= 0)
+ n++;
+ va_end(ap);
+
+ if((m = MBUF_ALLOC(n * 4 + 8)) == NULL) {
+ FAILURE("sscop: cannot allocate USTAT");
+ return;
+ }
+
+ va_start(ap, sscop);
+ while((f = va_arg(ap, int)) >= 0) {
+ seqno.sscop_null = 0;
+ seqno.sscop_n = f;
+ MBUF_APPEND32(m, seqno.sscop_null);
+ }
+ va_end(ap);
+
+ seqno.sscop_null = 0;
+ seqno.sscop_n = sscop->vr_mr;
+ MBUF_APPEND32(m, seqno.sscop_null);
+
+ pdu.sscop_null = 0;
+ pdu.sscop_type = PDU_USTAT;
+ pdu.sscop_ns = sscop->vr_r;
+ MBUF_APPEND32(m, pdu.sscop_null);
+
+ AAL_SEND(sscop, m);
+}
+
+/*
+ * Send ER PDU.
+ */
+static void
+send_er(struct sscop *sscop)
+{
+ union pdu pdu;
+ union bgn bgn;
+ struct SSCOP_MBUF_T *m;
+
+ pdu.sscop_null = 0;
+ pdu.sscop_type = PDU_ER;
+ pdu.sscop_ns = sscop->vr_mr;
+
+ bgn.sscop_null = 0;
+ bgn.sscop_bgns = sscop->vt_sq;
+
+ if((m = MBUF_ALLOC(8)) == NULL) {
+ FAILURE("sscop: cannot allocate ER");
+ return;
+ }
+ MBUF_APPEND32(m, bgn.sscop_null);
+ MBUF_APPEND32(m, pdu.sscop_null);
+
+ AAL_SEND(sscop, m);
+}
+
+/*
+ * Send POLL PDU.
+ */
+static void
+send_poll(struct sscop *sscop)
+{
+ union pdu pdu;
+ union seqno seqno;
+ struct SSCOP_MBUF_T *m;
+
+ seqno.sscop_null = 0;
+ seqno.sscop_n = sscop->vt_ps;
+
+ pdu.sscop_null = 0;
+ pdu.sscop_ns = sscop->vt_s;
+ pdu.sscop_type = PDU_POLL;
+
+ if((m = MBUF_ALLOC(8)) == NULL) {
+ FAILURE("sscop: cannot allocate POLL");
+ return;
+ }
+ MBUF_APPEND32(m, seqno.sscop_null);
+ MBUF_APPEND32(m, pdu.sscop_null);
+
+ AAL_SEND(sscop, m);
+}
+
+/*
+ * Send STAT PDU. List is already in buffer.
+ */
+static void
+send_stat(struct sscop *sscop, u_int nps, struct SSCOP_MBUF_T *m)
+{
+ union pdu pdu;
+ union seqno seqno;
+
+ seqno.sscop_null = 0;
+ seqno.sscop_n = nps;
+ MBUF_APPEND32(m, seqno.sscop_null);
+
+ seqno.sscop_null = 0;
+ seqno.sscop_n = sscop->vr_mr;
+ MBUF_APPEND32(m, seqno.sscop_null);
+
+ pdu.sscop_null = 0;
+ pdu.sscop_type = PDU_STAT;
+ pdu.sscop_ns = sscop->vr_r;
+ MBUF_APPEND32(m, pdu.sscop_null);
+
+ AAL_SEND(sscop, m);
+}
+
+/*
+ * Send ENDAK PDU.
+ */
+static void
+send_endak(struct sscop *sscop)
+{
+ union pdu pdu;
+ union seqno seqno;
+ struct SSCOP_MBUF_T *m;
+
+ seqno.sscop_null = 0;
+ pdu.sscop_null = 0;
+ pdu.sscop_type = PDU_ENDAK;
+
+ if((m = MBUF_ALLOC(8)) == NULL) {
+ FAILURE("sscop: cannot allocate ENDAK");
+ return;
+ }
+ MBUF_APPEND32(m, seqno.sscop_null);
+ MBUF_APPEND32(m, pdu.sscop_null);
+
+ AAL_SEND(sscop, m);
+}
+
+/*
+ * Send ERAK PDU.
+ */
+static void
+send_erak(struct sscop *sscop)
+{
+ union pdu pdu;
+ union seqno seqno;
+ struct SSCOP_MBUF_T *m;
+
+ seqno.sscop_null = 0;
+ pdu.sscop_null = 0;
+ pdu.sscop_type = PDU_ERAK;
+ pdu.sscop_ns = sscop->vr_mr;
+
+ if((m = MBUF_ALLOC(8)) == NULL) {
+ FAILURE("sscop: cannot allocate ERAK");
+ return;
+ }
+ MBUF_APPEND32(m, seqno.sscop_null);
+ MBUF_APPEND32(m, pdu.sscop_null);
+
+ AAL_SEND(sscop, m);
+}
+
+/*
+ * Send RS PDU
+ */
+static void
+send_rs(struct sscop *sscop, int resend, struct SSCOP_MBUF_T *uu)
+{
+ union pdu pdu;
+ union bgn bgn;
+ struct SSCOP_MBUF_T *m;
+
+ pdu.sscop_null = 0;
+ pdu.sscop_type = PDU_RS;
+ pdu.sscop_ns = resend ? sscop->rs_mr : sscop->vr_mr;
+
+ bgn.sscop_null = 0;
+ bgn.sscop_bgns = resend ? sscop->rs_sq : sscop->vt_sq;
+
+ sscop->rs_mr = pdu.sscop_ns;
+ sscop->rs_sq = bgn.sscop_bgns;
+
+ if(uu) {
+ if((m = MBUF_DUP(uu)) == NULL) {
+ FAILURE("sscop: cannot allocate RS");
+ return;
+ }
+ pdu.sscop_pl += MBUF_PAD4(m);
+ } else {
+ if((m = MBUF_ALLOC(8)) == NULL) {
+ FAILURE("sscop: cannot allocate RS");
+ return;
+ }
+ }
+
+ MBUF_APPEND32(m, bgn.sscop_null);
+ MBUF_APPEND32(m, pdu.sscop_null);
+
+ AAL_SEND(sscop, m);
+}
+
+/*
+ * Send RSAK pdu
+ */
+static void
+send_rsak(struct sscop *sscop)
+{
+ union pdu pdu;
+ union seqno seqno;
+ struct SSCOP_MBUF_T *m;
+
+ seqno.sscop_null = 0;
+ pdu.sscop_null = 0;
+ pdu.sscop_type = PDU_RSAK;
+ pdu.sscop_ns = sscop->vr_mr;
+
+ if((m = MBUF_ALLOC(8)) == NULL) {
+ FAILURE("sscop: cannot allocate RSAK");
+ return;
+ }
+
+ MBUF_APPEND32(m, seqno.sscop_null);
+ MBUF_APPEND32(m, pdu.sscop_null);
+
+ AAL_SEND(sscop, m);
+}
+
+/************************************************************/
+/*
+ * P 31; IDLE && AA-ESTABLISH-request
+ * arg is UU data (opt).
+ */
+static void
+sscop_idle_establish_req(struct sscop *sscop, struct sscop_msg *uu)
+{
+ u_int br = uu->rexmit;
+
+ SET_UU(uu_bgn, uu);
+
+ m_clear_transmitter(sscop);
+
+ sscop->clear_buffers = br;
+
+ sscop->vt_cc = 1;
+ sscop->vt_sq++;
+
+ m_initialize_mr(sscop);
+
+ send_bgn(sscop, sscop->uu_bgn);
+
+ TIMER_RESTART(sscop, cc);
+
+ sscop_set_state(sscop, SSCOP_OUT_PEND);
+}
+
+/*
+ * P 31: IDLE && BGN PDU
+ * arg is the received PDU (freed).
+ */
+static void
+sscop_idle_bgn(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+ union bgn bgn;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+
+ if(sscop->robustness) {
+ bgn.sscop_null = MBUF_STRIP32(msg->m);
+ sscop->vr_sq = bgn.sscop_bgns;
+ } else {
+ if(m_detect_retransmission(sscop, msg)) {
+ send_bgrej(sscop, sscop->uu_bgrej);
+ SSCOP_MSG_FREE(msg);
+ return;
+ }
+ (void)MBUF_STRIP32(msg->m);
+ }
+
+ sscop->vt_ms = pdu.sscop_ns;
+ sscop_set_state(sscop, SSCOP_IN_PEND);
+
+ AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, msg, pdu.sscop_pl, 0);
+}
+
+/*
+ * p 31: IDLE && ENDAK PDU
+ * p 34: OUT_PEND && ENDAK PDU
+ * p 34: OUT_PEND && SD PDU
+ * p 34: OUT_PEND && ERAK PDU
+ * p 34: OUT_PEND && END PDU
+ * p 34: OUT_PEND && STAT PDU
+ * p 34: OUT_PEND && USTAT PDU
+ * p 34: OUT_PEND && POLL PDU
+ * p 36: OUT_PEND && RS PDU
+ * p 36: OUT_PEND && RSAK PDU
+ * p 40: OUTGOING_DISCONNECT_PENDING && SD PDU
+ * p 40: OUTGOING_DISCONNECT_PENDING && BGAK PDU
+ * p 40: OUTGOING_DISCONNECT_PENDING && POLL PDU
+ * p 40: OUTGOING_DISCONNECT_PENDING && STAT PDU
+ * p 40: OUTGOING_DISCONNECT_PENDING && USTAT PDU
+ * p 41: OUTGOING_DISCONNECT_PENDING && ERAK PDU
+ * p 42: OUTGOING_DISCONNECT_PENDING && ER PDU
+ * p 42: OUTGOING_DISCONNECT_PENDING && RS PDU
+ * p 42: OUTGOING_DISCONNECT_PENDING && RSAK PDU
+ * p 43: OUTGOING_RESYNC && ER PDU
+ * p 43: OUTGOING_RESYNC && POLL PDU
+ * p 44: OUTGOING_RESYNC && STAT PDU
+ * p 44: OUTGOING_RESYNC && USTAT PDU
+ * p 45: OUTGOING_RESYNC && BGAK PDU
+ * p 45: OUTGOING_RESYNC && SD PDU
+ * p 45: OUTGOING_RESYNC && ERAK PDU
+ * P 60: READY && BGAK PDU
+ * P 60: READY && ERAK PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_ignore_pdu(struct sscop *sscop __unused, struct sscop_msg *msg)
+{
+ SSCOP_MSG_FREE(msg);
+}
+
+/*
+ * p 31: IDLE && END PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_idle_end(struct sscop *sscop, struct sscop_msg *msg)
+{
+ SSCOP_MSG_FREE(msg);
+ send_endak(sscop);
+}
+
+/*
+ * p 31: IDLE && ER PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_idle_er(struct sscop *sscop, struct sscop_msg *msg)
+{
+ SSCOP_MSG_FREE(msg);
+ MAAL_ERROR(sscop, 'L', 0);
+ FREE_UU(uu_end);
+ send_end(sscop, 1, NULL);
+}
+
+/*
+ * p 31: IDLE && BGREJ PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_idle_bgrej(struct sscop *sscop, struct sscop_msg *msg)
+{
+ SSCOP_MSG_FREE(msg);
+ MAAL_ERROR(sscop, 'D', 0);
+ FREE_UU(uu_end);
+}
+
+/*
+ * p 32: IDLE && POLL PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_idle_poll(struct sscop *sscop, struct sscop_msg *msg)
+{
+ SSCOP_MSG_FREE(msg);
+ MAAL_ERROR(sscop, 'G', 0);
+ FREE_UU(uu_end);
+ send_end(sscop, 1, NULL);
+}
+
+/*
+ * p 32: IDLE && SD PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_idle_sd(struct sscop *sscop, struct sscop_msg *msg)
+{
+ SSCOP_MSG_FREE(msg);
+ MAAL_ERROR(sscop, 'A', 0);
+ FREE_UU(uu_end);
+ send_end(sscop, 1, NULL);
+}
+
+/*
+ * p 32: IDLE && BGAK PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_idle_bgak(struct sscop *sscop, struct sscop_msg *msg)
+{
+ SSCOP_MSG_FREE(msg);
+ MAAL_ERROR(sscop, 'C', 0);
+ FREE_UU(uu_end);
+ send_end(sscop, 1, NULL);
+}
+
+/*
+ * p 32: IDLE && ERAK PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_idle_erak(struct sscop *sscop, struct sscop_msg *msg)
+{
+ SSCOP_MSG_FREE(msg);
+ MAAL_ERROR(sscop, 'M', 0);
+ FREE_UU(uu_end);
+ send_end(sscop, 1, NULL);
+}
+
+/*
+ * p 32: IDLE && STAT PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_idle_stat(struct sscop *sscop, struct sscop_msg *msg)
+{
+ SSCOP_MSG_FREE(msg);
+ MAAL_ERROR(sscop, 'H', 0);
+ FREE_UU(uu_end);
+ send_end(sscop, 1, NULL);
+}
+
+/*
+ * p 32: IDLE && USTAT PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_idle_ustat(struct sscop *sscop, struct sscop_msg *msg)
+{
+ SSCOP_MSG_FREE(msg);
+ MAAL_ERROR(sscop, 'I', 0);
+ FREE_UU(uu_end);
+ send_end(sscop, 1, NULL);
+}
+
+/*
+ * p 33: IDLE & RS PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_idle_rs(struct sscop *sscop, struct sscop_msg *msg)
+{
+ SSCOP_MSG_FREE(msg);
+ MAAL_ERROR(sscop, 'J', 0);
+ FREE_UU(uu_end);
+ send_end(sscop, 1, NULL);
+}
+
+/*
+ * p 33: IDLE & RSAK PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_idle_rsak(struct sscop *sscop, struct sscop_msg *msg)
+{
+ SSCOP_MSG_FREE(msg);
+ MAAL_ERROR(sscop, 'K', 0);
+ FREE_UU(uu_end);
+ send_end(sscop, 1, NULL);
+}
+
+/*
+ * p 33: IDLE && PDU_Q
+ * p XX: OUTPEND && PDU_Q
+ * p 39: IN_PEND && PDU_Q
+ * p 45: OUT_RESYNC_PEND && PDU_Q
+ * p 48: IN_RESYNC_PEND && PDU_Q
+ * no arg
+ */
+static void
+sscop_flush_pduq(struct sscop *sscop __unused, struct sscop_msg *unused __unused)
+{
+#if 0
+ MSGQ_CLEAR(&sscop->xq);
+#endif
+}
+
+/*
+ * p 34: OUT_PEND && BGAK PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_outpend_bgak(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+ (void)MBUF_STRIP32(msg->m);
+
+ TIMER_STOP(sscop, cc);
+ sscop->vt_ms = pdu.sscop_ns;
+
+ AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_confirm, msg, pdu.sscop_pl, 0);
+
+ m_initialize_state(sscop);
+ m_set_data_xfer_timers(sscop);
+
+ sscop_set_state(sscop, SSCOP_READY);
+}
+
+/*
+ * P 34: OUT_PEND && BGREJ PDU
+ */
+static void
+sscop_outpend_bgrej(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+ (void)MBUF_STRIP32(msg->m);
+
+ TIMER_STOP(sscop, cc);
+
+ AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication, msg, pdu.sscop_pl, 0);
+
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * P 35: OUT_PEND && TIMER_CC expiry
+ * no arg
+ */
+static void
+sscop_outpend_tcc(struct sscop *sscop, struct sscop_msg *unused __unused)
+{
+ if(sscop->vt_cc >= sscop->maxcc) {
+ MAAL_ERROR(sscop, 'O', 0);
+ FREE_UU(uu_end);
+ send_end(sscop, 1, NULL);
+
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+
+ sscop_set_state(sscop, SSCOP_IDLE);
+ } else {
+ sscop->vt_cc++;
+ send_bgn(sscop, sscop->uu_bgn);
+ TIMER_RESTART(sscop, cc);
+ }
+}
+
+/*
+ * P 35: OUT_PEND && RELEASE_REQ
+ * arg is UU
+ */
+static void
+sscop_outpend_release_req(struct sscop *sscop, struct sscop_msg *uu)
+{
+ SET_UU(uu_end, uu);
+
+ TIMER_STOP(sscop, cc);
+ sscop->vt_cc = 1;
+ send_end(sscop, 0, sscop->uu_end);
+ TIMER_RESTART(sscop, cc);
+
+ sscop_set_state(sscop, SSCOP_OUT_DIS_PEND);
+}
+
+/*
+ * P 36: OUT_PEND && BGN PDU
+ * arg is the received PDU (freed).
+ */
+static void
+sscop_outpend_bgn(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+
+ if(m_detect_retransmission(sscop, msg)) {
+ SSCOP_MSG_FREE(msg);
+ return;
+ }
+ (void)MBUF_STRIP32(msg->m);
+
+ TIMER_STOP(sscop, cc);
+
+ sscop->vt_ms = pdu.sscop_ns;
+
+ m_initialize_mr(sscop);
+
+ send_bgak(sscop, sscop->uu_bgak);
+
+ AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_confirm, msg, pdu.sscop_pl, 0);
+
+ m_initialize_state(sscop);
+
+ m_set_data_xfer_timers(sscop);
+
+ sscop_set_state(sscop, SSCOP_READY);
+}
+
+/*
+ * p 37: IN_PEND && AA-ESTABLISH.response
+ * arg is UU
+ */
+static void
+sscop_inpend_establish_resp(struct sscop *sscop, struct sscop_msg *uu)
+{
+ u_int br = uu->rexmit;
+
+ SET_UU(uu_bgak, uu);
+
+ m_clear_transmitter(sscop);
+ sscop->clear_buffers = br;
+ m_initialize_mr(sscop);
+ send_bgak(sscop, sscop->uu_bgak);
+ m_initialize_state(sscop);
+ m_set_data_xfer_timers(sscop);
+
+ sscop_set_state(sscop, SSCOP_READY);
+}
+
+/*
+ * p 37: IN_PEND && AA-RELEASE.request
+ * arg is uu.
+ */
+static void
+sscop_inpend_release_req(struct sscop *sscop, struct sscop_msg *uu)
+{
+ SET_UU(uu_bgrej, uu);
+
+ send_bgrej(sscop, sscop->uu_bgrej);
+
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 37: IN_PEND && BGN PDU
+ * arg is pdu. (freed)
+ */
+static void
+sscop_inpend_bgn(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+
+ if(m_detect_retransmission(sscop, msg)) {
+ SSCOP_MSG_FREE(msg);
+ return;
+ }
+ (void)MBUF_STRIP32(msg->m);
+
+ sscop->vt_ms = pdu.sscop_ns;
+
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0);
+ AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, msg, pdu.sscop_pl, 0);
+}
+
+/*
+ * p 37: IN_PEND && ER PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_inpend_er(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'L', 0);
+ SSCOP_MSG_FREE(msg);
+}
+
+/*
+ * p 37: IN_PEND && ENDAK PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_inpend_endak(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'F', 0);
+
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+
+ sscop_set_state(sscop, SSCOP_IDLE);
+
+ SSCOP_MSG_FREE(msg);
+}
+
+/*
+ * p 38: IN_PEND && BGAK PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_inpend_bgak(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'C', 0);
+
+ SSCOP_MSG_FREE(msg);
+}
+
+/*
+ * p 38: IN_PEND && BGREJ PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_inpend_bgrej(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'D', 0);
+
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+
+ SSCOP_MSG_FREE(msg);
+
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 38: IN_PEND && SD PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_inpend_sd(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'A', 0);
+
+ SSCOP_MSG_FREE(msg);
+
+ FREE_UU(uu_end);
+ send_end(sscop, 1, NULL);
+
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 38: IN_PEND && USTAT PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_inpend_ustat(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'I', 0);
+
+ SSCOP_MSG_FREE(msg);
+
+ FREE_UU(uu_end);
+ send_end(sscop, 1, NULL);
+
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 38: IN_PEND && STAT PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_inpend_stat(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'H', 0);
+
+ SSCOP_MSG_FREE(msg);
+
+ FREE_UU(uu_end);
+ send_end(sscop, 1, NULL);
+
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 38: IN_PEND && POLL PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_inpend_poll(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'G', 0);
+
+ SSCOP_MSG_FREE(msg);
+
+ FREE_UU(uu_end);
+ send_end(sscop, 1, NULL);
+
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 39: IN_PEND && ERAK PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_inpend_erak(struct sscop *sscop, struct sscop_msg *msg)
+{
+ SSCOP_MSG_FREE(msg);
+ MAAL_ERROR(sscop, 'M', 0);
+}
+
+/*
+ * p 39: IN_PEND & RS PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_inpend_rs(struct sscop *sscop, struct sscop_msg *msg)
+{
+ SSCOP_MSG_FREE(msg);
+ MAAL_ERROR(sscop, 'J', 0);
+}
+
+/*
+ * p 39: IN_PEND & RSAK PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_inpend_rsak(struct sscop *sscop, struct sscop_msg *msg)
+{
+ SSCOP_MSG_FREE(msg);
+ MAAL_ERROR(sscop, 'K', 0);
+}
+
+/*
+ * p 39: IN_PEND && END PDU
+ * arg is pdu (freed).
+ * no uui
+ */
+static void
+sscop_inpend_end(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+ (void)MBUF_STRIP32(msg->m);
+
+ send_endak(sscop);
+
+ AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication,
+ msg, pdu.sscop_pl, (u_int)pdu.sscop_s);
+
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 40: OUT_DIS_PEND && SSCOP_ESTABLISH_request
+ * no arg.
+ * no uui.
+ */
+static void
+sscop_outdis_establish_req(struct sscop *sscop, struct sscop_msg *uu)
+{
+ SET_UU(uu_bgn, uu);
+
+ TIMER_STOP(sscop, cc);
+ m_clear_transmitter(sscop);
+ sscop->clear_buffers = 1;
+ sscop->vt_cc = 1;
+ sscop->vt_sq++;
+ m_initialize_mr(sscop);
+ send_bgn(sscop, sscop->uu_bgn);
+ TIMER_RESTART(sscop, cc);
+
+ sscop_set_state(sscop, SSCOP_OUT_PEND);
+}
+
+/*
+ * p 41: OUT_DIS_PEND && END PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_outdis_end(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+ (void)MBUF_STRIP32(msg->m);
+
+ TIMER_STOP(sscop, cc);
+ send_endak(sscop);
+
+ AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_confirm, msg, pdu.sscop_pl, 0);
+
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 41: OUT_DIS_PEND && ENDAK PDU
+ * p 41: OUT_DIS_PEND && BGREJ PDU
+ * arg is pdu (freed)
+ */
+static void
+sscop_outdis_endak(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+ (void)MBUF_STRIP32(msg->m);
+
+ TIMER_STOP(sscop, cc);
+
+ AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_confirm, msg, pdu.sscop_pl, 0);
+
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 41: OUT_DIS_PEND && TIMER CC expiry
+ * no arg
+ */
+static void
+sscop_outdis_cc(struct sscop *sscop, struct sscop_msg *unused __unused)
+{
+ if(sscop->vt_cc >= sscop->maxcc) {
+ MAAL_ERROR(sscop, 'O', 0);
+ AAL_SIG(sscop, SSCOP_RELEASE_confirm);
+ sscop_set_state(sscop, SSCOP_IDLE);
+ } else {
+ sscop->vt_cc++;
+ send_end(sscop, sscop->last_end_src, sscop->uu_end);
+ TIMER_RESTART(sscop, cc);
+ }
+}
+
+/*
+ * p 42: OUT_DIS_PEND && BGN PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_outdis_bgn(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+
+ if(m_detect_retransmission(sscop, msg)) {
+ FREE_UU(uu_bgak);
+ send_bgak(sscop, NULL);
+ send_end(sscop, sscop->last_end_src, sscop->uu_end);
+ SSCOP_MSG_FREE(msg);
+
+ } else {
+ (void)MBUF_STRIP32(msg->m);
+
+ TIMER_STOP(sscop, cc);
+ sscop->vt_ms = pdu.sscop_ns;
+ AAL_SIG(sscop, SSCOP_RELEASE_confirm);
+ AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication,
+ msg, pdu.sscop_pl, 0);
+ sscop_set_state(sscop, SSCOP_IN_PEND);
+ }
+}
+
+/*
+ * p 43: OUT_RESYNC_PEND && BGN PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_outsync_bgn(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+
+ if(m_detect_retransmission(sscop, msg)) {
+ send_bgak(sscop, sscop->uu_bgak);
+ send_rs(sscop, 1, sscop->uu_rs);
+ SSCOP_MSG_FREE(msg);
+ } else {
+ (void)MBUF_STRIP32(msg->m);
+
+ TIMER_STOP(sscop, cc);
+ sscop->vt_ms = pdu.sscop_ns;
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0);
+ AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication,
+ msg, pdu.sscop_pl, 0);
+ sscop_set_state(sscop, SSCOP_IN_PEND);
+ }
+}
+
+/*
+ * p 43: OUT_RESYNC_PEND && ENDAK PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_outsync_endak(struct sscop *sscop, struct sscop_msg *msg)
+{
+ SSCOP_MSG_FREE(msg);
+ TIMER_STOP(sscop, cc);
+ MAAL_ERROR(sscop, 'F', 0);
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 43: OUT_RESYNC_PEND && BGREJ PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_outsync_bgrej(struct sscop *sscop, struct sscop_msg *msg)
+{
+ SSCOP_MSG_FREE(msg);
+ TIMER_STOP(sscop, cc);
+ MAAL_ERROR(sscop, 'D', 0);
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 43: OUT_RESYNC_PEND && END PDU
+ * arg is pdu (freed).
+ * no UU-data
+ */
+static void
+sscop_outsync_end(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+ (void)MBUF_STRIP32(msg->m);
+
+ TIMER_STOP(sscop, cc);
+ send_endak(sscop);
+ AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication, msg, pdu.sscop_pl,
+ (u_int)pdu.sscop_s);
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 44: OUT_RESYNC && TIMER CC expiry
+ */
+static void
+sscop_outsync_cc(struct sscop *sscop, struct sscop_msg *msg __unused)
+{
+ if(sscop->vt_cc == sscop->maxcc) {
+ MAAL_ERROR(sscop, 'O', 0);
+ FREE_UU(uu_end);
+ send_end(sscop, 1, NULL);
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+ sscop_set_state(sscop, SSCOP_IDLE);
+ } else {
+ sscop->vt_cc++;
+ send_rs(sscop, 1, sscop->uu_rs);
+ TIMER_RESTART(sscop, cc);
+ }
+}
+
+/*
+ * p 44: OUT_RESYNC && AA-RELEASE.request
+ * arg is UU
+ */
+static void
+sscop_outsync_release_req(struct sscop *sscop, struct sscop_msg *uu)
+{
+ SET_UU(uu_end, uu);
+
+ TIMER_STOP(sscop, cc);
+ sscop->vt_cc = 1;
+ send_end(sscop, 0, sscop->uu_end);
+ TIMER_RESTART(sscop, cc);
+ sscop_set_state(sscop, SSCOP_OUT_DIS_PEND);
+}
+
+/*
+ * p 45: OUT_RESYNC && RS PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_outsync_rs(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+
+ if(m_detect_retransmission(sscop, msg)) {
+ SSCOP_MSG_FREE(msg);
+ return;
+ }
+ (void)MBUF_STRIP32(msg->m);
+
+ TIMER_STOP(sscop, cc);
+ sscop->vt_ms = pdu.sscop_ns;
+ m_initialize_mr(sscop);
+ send_rsak(sscop);
+ AAL_UU_SIGNAL(sscop, SSCOP_RESYNC_confirm, msg, pdu.sscop_pl, 0);
+ m_initialize_state(sscop);
+ m_set_data_xfer_timers(sscop);
+ sscop_set_state(sscop, SSCOP_READY);
+}
+
+/*
+ * p 45: OUT_RESYNC && RSAK PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_outsync_rsak(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+
+ SSCOP_MSG_FREE(msg);
+
+ TIMER_STOP(sscop, cc);
+ sscop->vt_ms = pdu.sscop_ns;
+ AAL_SIG(sscop, SSCOP_RESYNC_confirm);
+ m_initialize_state(sscop);
+ m_set_data_xfer_timers(sscop);
+ sscop_set_state(sscop, SSCOP_READY);
+}
+
+/*
+ * p 46: IN_RESYNC_PEND && AA-RESYNC.response
+ */
+static void
+sscop_insync_sync_resp(struct sscop *sscop, struct sscop_msg *noarg __unused)
+{
+ m_initialize_mr(sscop);
+ send_rsak(sscop);
+ m_clear_transmitter(sscop);
+ m_initialize_state(sscop);
+ m_set_data_xfer_timers(sscop);
+ sscop_set_state(sscop, SSCOP_READY);
+}
+
+/*
+ * p 46: IN_RESYNC_PEND && AA-RELEASE.request
+ * arg is uu
+ */
+static void
+sscop_insync_release_req(struct sscop *sscop, struct sscop_msg *uu)
+{
+ SET_UU(uu_end, uu);
+
+ sscop->vt_cc = 1;
+ send_end(sscop, 0, sscop->uu_end);
+ TIMER_RESTART(sscop, cc);
+ sscop_set_state(sscop, SSCOP_OUT_DIS_PEND);
+}
+
+/*
+ * p 46: IN_RESYNC_PEND && ENDAK PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_insync_endak(struct sscop *sscop, struct sscop_msg *msg)
+{
+ SSCOP_MSG_FREE(msg);
+ MAAL_ERROR(sscop, 'F', 0);
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 46: IN_RESYNC_PEND && BGREJ PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_insync_bgrej(struct sscop *sscop, struct sscop_msg *msg)
+{
+ SSCOP_MSG_FREE(msg);
+ MAAL_ERROR(sscop, 'D', 0);
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 46: IN_RESYNC_PEND && END PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_insync_end(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+ (void)MBUF_STRIP32(msg->m);
+
+ send_endak(sscop);
+ AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication,
+ msg, pdu.sscop_pl, (u_int)pdu.sscop_s);
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 47: IN_RESYNC_PEND && ER PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_insync_er(struct sscop *sscop, struct sscop_msg *msg)
+{
+ SSCOP_MSG_FREE(msg);
+ MAAL_ERROR(sscop, 'L', 0);
+}
+
+/*
+ * p 47: IN_RESYNC_PEND && BGN PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_insync_bgn(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+
+ if(m_detect_retransmission(sscop, msg)) {
+ MAAL_ERROR(sscop, 'B', 0);
+ SSCOP_MSG_FREE(msg);
+ return;
+ }
+ (void)MBUF_STRIP32(msg->m);
+
+ sscop->vt_ms = pdu.sscop_ns;
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0);
+ AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, msg, pdu.sscop_pl, 0);
+
+ sscop_set_state(sscop, SSCOP_IN_PEND);
+}
+
+/*
+ * p 47: IN_RESYNC_PEND && SD PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_insync_sd(struct sscop *sscop, struct sscop_msg *msg)
+{
+ SSCOP_MSG_FREE(msg);
+ MAAL_ERROR(sscop, 'A', 0);
+ FREE_UU(uu_end);
+ send_end(sscop, 1, NULL);
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 47: IN_RESYNC_PEND && POLL PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_insync_poll(struct sscop *sscop, struct sscop_msg *msg)
+{
+ SSCOP_MSG_FREE(msg);
+ MAAL_ERROR(sscop, 'G', 0);
+ FREE_UU(uu_end);
+ send_end(sscop, 1, NULL);
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 47: IN_RESYNC_PEND && STAT PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_insync_stat(struct sscop *sscop, struct sscop_msg *msg)
+{
+ SSCOP_MSG_FREE(msg);
+ MAAL_ERROR(sscop, 'H', 0);
+ FREE_UU(uu_end);
+ send_end(sscop, 1, NULL);
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 47: IN_RESYNC_PEND && USTAT PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_insync_ustat(struct sscop *sscop, struct sscop_msg *msg)
+{
+ SSCOP_MSG_FREE(msg);
+ MAAL_ERROR(sscop, 'I', 0);
+ FREE_UU(uu_end);
+ send_end(sscop, 1, NULL);
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 48: IN_RESYNC_PEND && BGAK PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_insync_bgak(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'C', 0);
+ SSCOP_MSG_FREE(msg);
+}
+
+/*
+ * p 48: IN_RESYNC_PEND && ERAK PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_insync_erak(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'M', 0);
+ SSCOP_MSG_FREE(msg);
+}
+
+/*
+ * p 48: IN_RESYNC_PEND && RS PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_insync_rs(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+
+ if(m_detect_retransmission(sscop, msg)) {
+ SSCOP_MSG_FREE(msg);
+ return;
+ }
+ SSCOP_MSG_FREE(msg);
+ MAAL_ERROR(sscop, 'J', 0);
+}
+
+/*
+ * p 48: IN_RESYNC_PEND && RSAK PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_insync_rsak(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'K', 0);
+ SSCOP_MSG_FREE(msg);
+}
+
+
+/*
+ * p 49: OUT_REC_PEND && AA-DATA.request
+ * arg is message (queued).
+ */
+static void
+sscop_outrec_userdata(struct sscop *sscop, struct sscop_msg *msg)
+{
+ if(!sscop->clear_buffers) {
+ MSGQ_APPEND(&sscop->xq, msg);
+ sscop_signal(sscop, SIG_PDU_Q, msg);
+ } else {
+ SSCOP_MSG_FREE(msg);
+ }
+}
+
+/*
+ * p 49: OUT_REC_PEND && BGAK PDU
+ * arg is pdu (freed)
+ */
+static void
+sscop_outrec_bgak(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'C', 0);
+
+ SSCOP_MSG_FREE(msg);
+}
+
+/*
+ * p 49: OUT_REC_PEND && ERAK PDU
+ * arg is pdu (freed)
+ */
+static void
+sscop_outrec_erak(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+
+ TIMER_STOP(sscop, cc);
+ sscop->vt_ms = pdu.sscop_ns;
+ m_deliver_data(sscop);
+
+ AAL_SIG(sscop, SSCOP_RECOVER_indication);
+
+ sscop_set_state(sscop, SSCOP_REC_PEND);
+
+ SSCOP_MSG_FREE(msg);
+}
+
+/*
+ * p 49: OUT_REC_PEND && END PDU
+ * arg is pdu (freed)
+ */
+static void
+sscop_outrec_end(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+ (void)MBUF_STRIP32(msg->m);
+
+ TIMER_STOP(sscop, cc);
+ send_endak(sscop);
+ AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication,
+ msg, pdu.sscop_pl, (u_int)pdu.sscop_s);
+
+ MSGQ_CLEAR(&sscop->rbuf);
+
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 49: OUT_REC_PEND && ENDAK PDU
+ * arg is pdu (freed)
+ */
+static void
+sscop_outrec_endak(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'F', 0);
+ TIMER_STOP(sscop, cc);
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+ MSGQ_CLEAR(&sscop->rbuf);
+
+ sscop_set_state(sscop, SSCOP_IDLE);
+
+ SSCOP_MSG_FREE(msg);
+}
+
+/*
+ * p 49: OUT_REC_PEND && BGREJ PDU
+ * arg is pdu (freed)
+ */
+static void
+sscop_outrec_bgrej(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'D', 0);
+ TIMER_STOP(sscop, cc);
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+ MSGQ_CLEAR(&sscop->rbuf);
+
+ sscop_set_state(sscop, SSCOP_IDLE);
+
+ SSCOP_MSG_FREE(msg);
+}
+
+/*
+ * p 50: OUT_REC_PEND && TIMER CC expiry
+ * no arg.
+ */
+static void
+sscop_outrec_cc(struct sscop *sscop, struct sscop_msg *unused __unused)
+{
+ if(sscop->vt_cc >= sscop->maxcc) {
+ MAAL_ERROR(sscop, 'O', 0);
+ FREE_UU(uu_end);
+ send_end(sscop, 1, NULL);
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+ MSGQ_CLEAR(&sscop->rbuf);
+ sscop_set_state(sscop, SSCOP_IDLE);
+ } else {
+ sscop->vt_cc++;
+ send_er(sscop);
+ TIMER_RESTART(sscop, cc);
+ }
+}
+
+/*
+ * p 50: OUT_REC_PEND && SSCOP_RELEASE_request
+ * arg is UU
+ */
+static void
+sscop_outrec_release_req(struct sscop *sscop, struct sscop_msg *uu)
+{
+ SET_UU(uu_end, uu);
+
+ TIMER_STOP(sscop, cc);
+ sscop->vt_cc = 1;
+ send_end(sscop, 0, sscop->uu_end);
+ MSGQ_CLEAR(&sscop->rbuf);
+ TIMER_RESTART(sscop, cc);
+
+ sscop_set_state(sscop, SSCOP_OUT_DIS_PEND);
+}
+
+/*
+ * p 51: OUT_REC_PEND && AA-RESYNC.request
+ * arg is uu
+ */
+static void
+sscop_outrec_sync_req(struct sscop *sscop, struct sscop_msg *uu)
+{
+ SET_UU(uu_rs, uu);
+
+ TIMER_STOP(sscop, cc);
+ sscop->vt_cc = 1;
+ sscop->vt_sq++;
+ m_initialize_mr(sscop);
+ send_rs(sscop, 0, sscop->uu_rs);
+ m_clear_transmitter(sscop);
+ MSGQ_CLEAR(&sscop->rbuf);
+ TIMER_RESTART(sscop, cc);
+}
+
+/*
+ * p 51: OUT_REC_PEND && BGN PDU
+ * arg is pdu (freed).
+ * no uui
+ */
+static void
+sscop_outrec_bgn(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+
+ if(m_detect_retransmission(sscop, msg)) {
+ MAAL_ERROR(sscop, 'B', 0);
+ SSCOP_MSG_FREE(msg);
+ } else {
+ (void)MBUF_STRIP32(msg->m);
+
+ TIMER_STOP(sscop, cc);
+ sscop->vt_ms = pdu.sscop_ns;
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0);
+ AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication,
+ msg, pdu.sscop_pl, 0);
+ MSGQ_CLEAR(&sscop->rbuf);
+
+ sscop_set_state(sscop, SSCOP_IN_PEND);
+ }
+}
+
+/*
+ * p 51: OUT_REC_PEND && ER PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_outrec_er(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+
+ if(m_detect_retransmission(sscop, msg)) {
+ MAAL_ERROR(sscop, 'L', 0);
+ } else {
+ TIMER_STOP(sscop, cc);
+ sscop->vt_ms = pdu.sscop_ns;
+ m_initialize_mr(sscop);
+ send_erak(sscop);
+ m_deliver_data(sscop);
+
+ AAL_SIG(sscop, SSCOP_RECOVER_indication);
+
+ sscop_set_state(sscop, SSCOP_REC_PEND);
+ }
+
+ SSCOP_MSG_FREE(msg);
+}
+
+/*
+ * p 52: OUT_REC_PEND && SD PDU queued
+ * no arg.
+ */
+static void
+sscop_outrec_pduq(struct sscop *sscop, struct sscop_msg *msg)
+{
+ sscop_save_signal(sscop, SIG_PDU_Q, msg);
+}
+
+/*
+ * p 52: OUT_REC_PEND && RSAK PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_outrec_rsak(struct sscop *sscop, struct sscop_msg *msg)
+{
+ SSCOP_MSG_FREE(msg);
+ MAAL_ERROR(sscop, 'K', 0);
+}
+
+/*
+ * p 52: OUT_REC_PEND && RS PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_outrec_rs(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+
+ if(m_detect_retransmission(sscop, msg)) {
+ SSCOP_MSG_FREE(msg);
+ MAAL_ERROR(sscop, 'J', 0);
+ return;
+ }
+ (void)MBUF_STRIP32(msg->m);
+
+ TIMER_STOP(sscop, cc);
+ sscop->vt_ms = pdu.sscop_ns;
+ AAL_UU_SIGNAL(sscop, SSCOP_RESYNC_indication, msg, pdu.sscop_pl, 0);
+ MSGQ_CLEAR(&sscop->rbuf);
+ sscop_set_state(sscop, SSCOP_IN_RESYNC_PEND);
+}
+
+/*
+ * p 53: REC_PEND && BGAK PDU
+ * arg is pdu (freed)
+ */
+static void
+sscop_rec_bgak(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'C', 0);
+
+ SSCOP_MSG_FREE(msg);
+}
+
+/*
+ * p 53: REC_PEND && END PDU
+ * arg is pdu (freed)
+ * no uui
+ */
+static void
+sscop_rec_end(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+ (void)MBUF_STRIP32(msg->m);
+
+ send_endak(sscop);
+ AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication,
+ msg, pdu.sscop_pl, (u_int)pdu.sscop_s);
+
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 53: REC_PEND && ENDAK PDU
+ * arg is pdu (freed)
+ */
+static void
+sscop_rec_endak(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'F', 0);
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+ sscop_set_state(sscop, SSCOP_IDLE);
+ SSCOP_MSG_FREE(msg);
+}
+
+/*
+ * p 53: REC_PEND && BGREJ PDU
+ * arg is pdu (freed)
+ */
+static void
+sscop_rec_bgrej(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'D', 0);
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+ sscop_set_state(sscop, SSCOP_IDLE);
+ SSCOP_MSG_FREE(msg);
+}
+
+/*
+ * p 54: REC_PEND && RELEASE
+ * arg is UU
+ */
+static void
+sscop_rec_release_req(struct sscop *sscop, struct sscop_msg *uu)
+{
+ SET_UU(uu_end, uu);
+
+ sscop->vt_cc = 1;
+ send_end(sscop, 0, sscop->uu_end);
+ TIMER_RESTART(sscop, cc);
+
+ sscop_set_state(sscop, SSCOP_OUT_DIS_PEND);
+}
+
+/*
+ * p 54: REC_PEND && RSAK PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_rec_rsak(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'K', 0);
+ SSCOP_MSG_FREE(msg);
+}
+
+
+/*
+ * p 54: REC_PEND && RS PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_rec_rs(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+
+ if(m_detect_retransmission(sscop, msg)) {
+ SSCOP_MSG_FREE(msg);
+ MAAL_ERROR(sscop, 'J', 0);
+ return;
+ }
+ (void)MBUF_STRIP32(msg->m);
+
+ sscop->vt_ms = pdu.sscop_ns;
+ AAL_UU_SIGNAL(sscop, SSCOP_RESYNC_indication, msg, pdu.sscop_pl, 0);
+
+ sscop_set_state(sscop, SSCOP_IN_RESYNC_PEND);
+}
+
+/*
+ * p 54: REC_PEND && RECOVER response
+ * no arg
+ */
+static void
+sscop_rec_recover(struct sscop *sscop, struct sscop_msg *unused __unused)
+{
+ if(!sscop->clear_buffers) {
+ MSGQ_CLEAR(&sscop->xbuf);
+ }
+ m_initialize_state(sscop);
+ m_set_data_xfer_timers(sscop);
+
+ sscop_set_state(sscop, SSCOP_READY);
+}
+
+/*
+ * p 54: REC_PEND && RESYNC request
+ * arg is uu
+ */
+static void
+sscop_rec_sync_req(struct sscop *sscop, struct sscop_msg *uu)
+{
+ SET_UU(uu_rs, uu);
+
+ m_clear_transmitter(sscop);
+ sscop->vt_cc = 1;
+ sscop->vt_sq++;
+ m_initialize_mr(sscop);
+ send_rs(sscop, 0, sscop->uu_rs);
+ TIMER_RESTART(sscop, cc);
+
+ sscop_set_state(sscop, SSCOP_OUT_RESYNC_PEND);
+}
+
+/*
+ * p 55: REC_PEND && SD PDU queued
+ * no arg
+ */
+static void
+sscop_rec_pduq(struct sscop *sscop, struct sscop_msg *msg)
+{
+ sscop_save_signal(sscop, SIG_PDU_Q, msg);
+}
+
+/*
+ * p 55: REC_PEND && ER PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_rec_er(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+
+ if(m_detect_retransmission(sscop, msg)) {
+ send_erak(sscop);
+ } else {
+ MAAL_ERROR(sscop, 'L', 0);
+ }
+ SSCOP_MSG_FREE(msg);
+}
+
+/*
+ * p 55: REC_PEND && BGN PDU
+ * arg is pdu (freed)
+ * no uui
+ */
+static void
+sscop_rec_bgn(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+
+ if(m_detect_retransmission(sscop, msg)) {
+ MAAL_ERROR(sscop, 'B', 0);
+ SSCOP_MSG_FREE(msg);
+ return;
+ }
+ (void)MBUF_STRIP32(msg->m);
+
+ sscop->vt_ms = pdu.sscop_ns;
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0);
+ AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, msg, pdu.sscop_pl, 0);
+
+ sscop_set_state(sscop, SSCOP_IN_PEND);
+}
+
+/*
+ * p 55: REC_PEND && STAT PDU
+ * arg is pdu (freed)
+ */
+static void
+sscop_rec_stat(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'H', 0);
+ FREE_UU(uu_end);
+ send_end(sscop, 1, NULL);
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+ sscop_set_state(sscop, SSCOP_IDLE);
+ SSCOP_MSG_FREE(msg);
+}
+
+/*
+ * p 55: REC_PEND && USTAT PDU
+ * arg is pdu (freed)
+ */
+static void
+sscop_rec_ustat(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'I', 0);
+ FREE_UU(uu_end);
+ send_end(sscop, 1, NULL);
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+ sscop_set_state(sscop, SSCOP_IDLE);
+ SSCOP_MSG_FREE(msg);
+}
+
+/*
+ * p 56: IN_REC_PEND && AA-RECOVER.response
+ * no arg
+ */
+static void
+sscop_inrec_recover(struct sscop *sscop, struct sscop_msg *unused __unused)
+{
+ if(!sscop->clear_buffers) {
+ MSGQ_CLEAR(&sscop->xbuf);
+ }
+ m_initialize_mr(sscop);
+ send_erak(sscop);
+ m_initialize_state(sscop);
+ m_set_data_xfer_timers(sscop);
+
+ sscop_set_state(sscop, SSCOP_READY);
+}
+
+/*
+ * p 56: IN_REC_PEND && SD PDU queued
+ * no arg
+ */
+static void
+sscop_inrec_pduq(struct sscop *sscop, struct sscop_msg *msg)
+{
+ sscop_save_signal(sscop, SIG_PDU_Q, msg);
+}
+
+/*
+ * p 56: IN_REC_PEND && AA-RELEASE.request
+ * arg is UU
+ */
+static void
+sscop_inrec_release_req(struct sscop *sscop, struct sscop_msg *uu)
+{
+ SET_UU(uu_end, uu);
+
+ sscop->vt_cc = 1;
+ send_end(sscop, 0, sscop->uu_end);
+ TIMER_RESTART(sscop, cc);
+
+ sscop_set_state(sscop, SSCOP_OUT_DIS_PEND);
+}
+
+/*
+ * p 56: IN_REC_PEND && END PDU
+ * arg is pdu (freed).
+ * no uui
+ */
+static void
+sscop_inrec_end(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+ (void)MBUF_STRIP32(msg->m);
+
+ send_endak(sscop);
+ AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication,
+ msg, pdu.sscop_pl, (u_int)pdu.sscop_s);
+
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 56: IN_REC_PEND && RESYNC_REQ
+ */
+static void
+sscop_inrec_sync_req(struct sscop *sscop, struct sscop_msg *uu)
+{
+ SET_UU(uu_rs, uu);
+
+ m_clear_transmitter(sscop);
+ sscop->vt_cc = 1;
+ sscop->vt_sq++;
+ m_initialize_mr(sscop);
+ send_rs(sscop, 0, sscop->uu_rs);
+ TIMER_RESTART(sscop, cc);
+
+ sscop_set_state(sscop, SSCOP_OUT_RESYNC_PEND);
+}
+
+
+/*
+ * p 57: IN_REC_PEND && ENDAK PDU
+ * arg is pdu (freed)
+ */
+static void
+sscop_inrec_endak(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'F', 0);
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+ SSCOP_MSG_FREE(msg);
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 57: IN_REC_PEND && BGREJ PDU
+ * arg is pdu (freed)
+ */
+static void
+sscop_inrec_bgrej(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'D', 0);
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+ SSCOP_MSG_FREE(msg);
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 57: IN_REC_PEND && USTAT PDU
+ * arg is pdu (freed)
+ */
+static void
+sscop_inrec_ustat(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'I', 0);
+ FREE_UU(uu_end);
+ send_end(sscop, 1, NULL);
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+ SSCOP_MSG_FREE(msg);
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 57: IN_REC_PEND && STAT PDU
+ * arg is pdu (freed)
+ */
+static void
+sscop_inrec_stat(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'H', 0);
+ FREE_UU(uu_end);
+ send_end(sscop, 1, NULL);
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+ SSCOP_MSG_FREE(msg);
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 57: IN_REC_PEND && POLL PDU
+ * arg is pdu (freed)
+ */
+static void
+sscop_inrec_poll(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'G', 0);
+ FREE_UU(uu_end);
+ send_end(sscop, 1, NULL);
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+ SSCOP_MSG_FREE(msg);
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 57: IN_REC_PEND && SD PDU
+ * arg is pdu (freed)
+ */
+static void
+sscop_inrec_sd(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'A', 0);
+ FREE_UU(uu_end);
+ send_end(sscop, 1, NULL);
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+ SSCOP_MSG_FREE(msg);
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 58: IN_REC_PEND && RSAK PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_inrec_rsak(struct sscop *sscop, struct sscop_msg *msg)
+{
+ SSCOP_MSG_FREE(msg);
+ MAAL_ERROR(sscop, 'K', 0);
+}
+
+/*
+ * p 58: IN_REC_PEND && RS PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_inrec_rs(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+
+ if(m_detect_retransmission(sscop, msg)) {
+ SSCOP_MSG_FREE(msg);
+ MAAL_ERROR(sscop, 'J', 0);
+ return;
+ }
+ (void)MBUF_STRIP32(msg->m);
+
+ sscop->vt_ms = pdu.sscop_ns;
+ AAL_UU_SIGNAL(sscop, SSCOP_RESYNC_indication, msg, pdu.sscop_pl, 0);
+
+ sscop_set_state(sscop, SSCOP_IN_RESYNC_PEND);
+}
+
+/*
+ * p 59: IN_REC_PEND && ER PDU
+ * arg is pdu (freed)
+ */
+static void
+sscop_inrec_er(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+
+ if(!m_detect_retransmission(sscop, msg)) {
+ MAAL_ERROR(sscop, 'L', 0);
+ }
+
+ SSCOP_MSG_FREE(msg);
+}
+
+/*
+ * p 59: IN_REC_PEND && BGN PDU
+ * arg is pdu (freed).
+ * no uui
+ */
+static void
+sscop_inrec_bgn(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+
+ if(m_detect_retransmission(sscop, msg)) {
+ MAAL_ERROR(sscop, 'B', 0);
+ SSCOP_MSG_FREE(msg);
+ return;
+ }
+ (void)MBUF_STRIP32(msg->m);
+
+ sscop->vt_ms = pdu.sscop_ns;
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0);
+ AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, msg, pdu.sscop_pl, 0);
+
+ sscop_set_state(sscop, SSCOP_IN_PEND);
+}
+
+/*
+ * p 59: IN_REC_PEND && BGAK PDU
+ * arg is pdu (freed)
+ * no uui
+ */
+static void
+sscop_inrec_bgak(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'C', 0);
+ SSCOP_MSG_FREE(msg);
+}
+
+/*
+ * p 59: IN_REC_PEND && ERAK PDU
+ * arg is pdu (freed)
+ * no uui
+ */
+static void
+sscop_inrec_erak(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MAAL_ERROR(sscop, 'M', 0);
+ SSCOP_MSG_FREE(msg);
+}
+
+/*
+ * p 60: READY && RESYNC request
+ * arg is UU
+ */
+static void
+sscop_ready_sync_req(struct sscop *sscop, struct sscop_msg *uu)
+{
+ SET_UU(uu_rs, uu);
+
+ m_reset_data_xfer_timers(sscop);
+ sscop->vt_cc = 1;
+ sscop->vt_sq++;
+ m_initialize_mr(sscop);
+ send_rs(sscop, 0, sscop->uu_rs);
+ m_release_buffers(sscop);
+ TIMER_RESTART(sscop, cc);
+
+ sscop_set_state(sscop, SSCOP_OUT_RESYNC_PEND);
+}
+
+
+/*
+ * p 60: READY && AA-RELEASE.request
+ * arg is uu.
+ */
+static void
+sscop_ready_release_req(struct sscop *sscop, struct sscop_msg *uu)
+{
+ SET_UU(uu_end, uu);
+
+ m_reset_data_xfer_timers(sscop);
+ sscop->vt_cc = 1;
+ send_end(sscop, 0, sscop->uu_end);
+ m_prepare_retrieval(sscop);
+ TIMER_RESTART(sscop, cc);
+
+ sscop_set_state(sscop, SSCOP_OUT_DIS_PEND);
+}
+
+/*
+ * p 61: READY && ER PDU
+ * arg is pdu (freed).
+ */
+static void
+sscop_ready_er(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+
+ if(m_detect_retransmission(sscop, msg)) {
+ TIMER_RESTART(sscop, nr);
+ send_erak(sscop);
+ } else {
+ m_reset_data_xfer_timers(sscop);
+ sscop->vt_ms = pdu.sscop_ns;
+ m_prepare_recovery(sscop);
+ m_deliver_data(sscop);
+
+ AAL_SIG(sscop, SSCOP_RECOVER_indication);
+
+ sscop_set_state(sscop, SSCOP_IN_REC_PEND);
+ }
+
+ SSCOP_MSG_FREE(msg);
+}
+
+/*
+ * p 61: READY && BGN PDU
+ * arg is pdu (freed)
+ */
+static void
+sscop_ready_bgn(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+
+ if(m_detect_retransmission(sscop, msg)) {
+ TIMER_RESTART(sscop, nr);
+ send_bgak(sscop, sscop->uu_bgak);
+ SSCOP_MSG_FREE(msg);
+ return;
+ }
+ (void)MBUF_STRIP32(msg->m);
+
+ m_reset_data_xfer_timers(sscop);
+ sscop->vt_ms = pdu.sscop_ns;
+
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0);
+ AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, msg, pdu.sscop_pl, 0);
+
+ m_prepare_retrieval(sscop);
+
+ sscop_set_state(sscop, SSCOP_IN_PEND);
+}
+
+/*
+ * p 62: READY && ENDAK PDU
+ * arg is pdu (freed)
+ */
+static void
+sscop_ready_endak(struct sscop *sscop, struct sscop_msg *msg)
+{
+ m_reset_data_xfer_timers(sscop);
+ MAAL_ERROR(sscop, 'F', 0);
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+ m_prepare_retrieval(sscop);
+ SSCOP_MSG_FREE(msg);
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 62: READY && BGREJ PDU
+ * arg is pdu (freed)
+ */
+static void
+sscop_ready_bgrej(struct sscop *sscop, struct sscop_msg *msg)
+{
+ m_reset_data_xfer_timers(sscop);
+ MAAL_ERROR(sscop, 'D', 0);
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+ m_prepare_retrieval(sscop);
+ SSCOP_MSG_FREE(msg);
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 62: READY && RS PDU
+ * arg is pdu (freed)
+ */
+static void
+sscop_ready_rs(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+
+ if(m_detect_retransmission(sscop, msg)) {
+ SSCOP_MSG_FREE(msg);
+ TIMER_RESTART(sscop, nr);
+ send_rsak(sscop);
+ return;
+ }
+ (void)MBUF_STRIP32(msg->m);
+
+ m_reset_data_xfer_timers(sscop);
+ sscop->vt_ms = pdu.sscop_ns;
+ AAL_UU_SIGNAL(sscop, SSCOP_RESYNC_indication, msg, pdu.sscop_pl, 0);
+ m_prepare_retrieval(sscop);
+
+ sscop_set_state(sscop, SSCOP_IN_RESYNC_PEND);
+}
+
+/*
+ * p 62: READY && END PDU
+ * arg is pdu (freed)
+ */
+static void
+sscop_ready_end(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+ (void)MBUF_STRIP32(msg->m);
+
+ m_reset_data_xfer_timers(sscop);
+ send_endak(sscop);
+ AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication,
+ msg, pdu.sscop_pl, (u_int)pdu.sscop_s);
+ m_prepare_retrieval(sscop);
+
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 63: READY && POLL expiry
+ */
+static void
+sscop_ready_tpoll(struct sscop *sscop, struct sscop_msg *unused __unused)
+{
+ sscop->vt_ps++;
+ send_poll(sscop);
+ sscop->vt_pd = 0;
+ m_set_poll_timer(sscop);
+}
+
+/*
+ * p 63: READY && KEEP_ALIVE expiry
+ */
+static void
+sscop_ready_tka(struct sscop *sscop, struct sscop_msg *unused __unused)
+{
+ sscop->vt_ps++;
+ send_poll(sscop);
+ sscop->vt_pd = 0;
+ m_set_poll_timer(sscop);
+}
+
+/*
+ * p 63: READY && IDLE expiry
+ */
+static void
+sscop_ready_tidle(struct sscop *sscop, struct sscop_msg *unused __unused)
+{
+ TIMER_RESTART(sscop, nr);
+ sscop->vt_ps++;
+ send_poll(sscop);
+ sscop->vt_pd = 0;
+ m_set_poll_timer(sscop);
+}
+
+/*
+ * p 63: READY && NO_RESPONSE expiry
+ * no arg
+ */
+static void
+sscop_ready_nr(struct sscop *sscop, struct sscop_msg *unused __unused)
+{
+ m_reset_data_xfer_timers(sscop);
+ MAAL_ERROR(sscop, 'P', 0);
+ FREE_UU(uu_end);
+ send_end(sscop, 1, NULL);
+ AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
+ m_prepare_retrieval(sscop);
+ sscop_set_state(sscop, SSCOP_IDLE);
+}
+
+/*
+ * p 63: READY && AA-DATA.request
+ * arg is message (queued).
+ */
+static void
+sscop_ready_userdata(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MSGQ_APPEND(&sscop->xq, msg);
+
+ sscop_signal(sscop, SIG_PDU_Q, msg);
+}
+
+/*
+ * p 64: READY && SD PDU queued up
+ * arg is unused.
+ */
+static void
+sscop_ready_pduq(struct sscop *sscop, struct sscop_msg *unused __unused)
+{
+ struct sscop_msg *msg;
+
+ if(sscop->rxq != 0) {
+ TAILQ_FOREACH(msg, &sscop->xbuf, link)
+ if(msg->rexmit)
+ break;
+ ASSERT(msg != NULL);
+ msg->rexmit = 0;
+ sscop->rxq--;
+ send_sd(sscop, msg->m, msg->seqno);
+ msg->poll_seqno = sscop->vt_ps;
+ if(sscop->poll_after_rex && sscop->rxq == 0)
+ goto poll; /* -> A */
+ else
+ goto maybe_poll; /* -> B */
+
+ }
+ if(MSGQ_EMPTY(&sscop->xq))
+ return;
+
+ if(sscop->vt_s >= sscop->vt_ms) {
+ /* Send windows closed */
+ TIMER_STOP(sscop, idle);
+ TIMER_RESTART(sscop, nr);
+ goto poll; /* -> A */
+
+ } else {
+ msg = MSGQ_GET(&sscop->xq);
+ msg->seqno = sscop->vt_s;
+ send_sd(sscop, msg->m, msg->seqno);
+ msg->poll_seqno = sscop->vt_ps;
+ sscop->vt_s++;
+ MSGQ_APPEND(&sscop->xbuf, msg);
+ goto maybe_poll; /* -> B */
+ }
+
+ /*
+ * p 65: Poll handling
+ */
+ maybe_poll: /* label B */
+ sscop->vt_pd++;
+ if(TIMER_ISACT(sscop, poll)) {
+ if(sscop->vt_pd < sscop->maxpd)
+ return;
+ } else {
+ if(TIMER_ISACT(sscop, idle)) {
+ TIMER_STOP(sscop, idle);
+ TIMER_RESTART(sscop, nr);
+ } else {
+ TIMER_STOP(sscop, ka);
+ }
+ if(sscop->vt_pd < sscop->maxpd) {
+ TIMER_RESTART(sscop, poll);
+ return;
+ }
+ }
+ poll: /* label A */
+ sscop->vt_ps++;
+ send_poll(sscop);
+ sscop->vt_pd = 0;
+ TIMER_RESTART(sscop, poll);
+}
+
+/*
+ * p 67: common recovery start
+ */
+static void
+sscop_recover(struct sscop *sscop)
+{
+ sscop->vt_cc = 1;
+ sscop->vt_sq++;
+
+ m_initialize_mr(sscop);
+ send_er(sscop);
+ m_prepare_recovery(sscop);
+
+ TIMER_RESTART(sscop, cc);
+
+ sscop_set_state(sscop, SSCOP_OUT_REC_PEND);
+}
+
+/*
+ * p 66: READY && SD PDU
+ * arg is received message.
+ */
+static void
+sscop_ready_sd(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+ u_int sn;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+ msg->seqno = pdu.sscop_ns;
+
+ /* Fix padding */
+ MBUF_UNPAD(msg->m, pdu.sscop_pl);
+
+ if(msg->seqno >= sscop->vr_mr) {
+ /* message outside window */
+ if(sscop->vr_h < sscop->vr_mr) {
+ send_ustat(sscop, sscop->vr_h, sscop->vr_mr, -1);
+ sscop->vr_h = sscop->vr_mr;
+ }
+ SSCOP_MSG_FREE(msg);
+ return;
+ }
+
+ if(msg->seqno == sscop->vr_r) {
+ if(msg->seqno == sscop->vr_h) {
+ sscop->vr_r = msg->seqno + 1;
+ sscop->vr_h = msg->seqno + 1;
+
+ AAL_DATA(sscop, SSCOP_DATA_indication,
+ msg->m, msg->seqno);
+ msg->m = NULL;
+ SSCOP_MSG_FREE(msg);
+
+ return;
+ }
+ for(;;) {
+ AAL_DATA(sscop, SSCOP_DATA_indication,
+ msg->m, msg->seqno);
+ msg->m = NULL;
+ SSCOP_MSG_FREE(msg);
+
+ sscop->vr_r++;
+ if((msg = MSGQ_PEEK(&sscop->rbuf)) == NULL)
+ break;
+ sn = msg->seqno;
+ ASSERT(sn >= sscop->vr_r);
+ if(sn != sscop->vr_r)
+ break;
+ msg = MSGQ_GET(&sscop->rbuf);
+ }
+ return;
+ }
+
+ /* Messages were lost */
+
+ /* XXX Flow control */
+ if(msg->seqno == sscop->vr_h) {
+ QINSERT(&sscop->rbuf, msg);
+ sscop->vr_h++;
+ return;
+ }
+ if(sscop->vr_h < msg->seqno) {
+ QINSERT(&sscop->rbuf, msg);
+ send_ustat(sscop, sscop->vr_h, msg->seqno, -1);
+ sscop->vr_h = msg->seqno + 1;
+ return;
+ }
+
+ if(QFIND(&sscop->rbuf, msg->seqno) == NULL) {
+ QINSERT(&sscop->rbuf, msg);
+ return;
+ }
+
+ /* error: start recovery */
+ SSCOP_MSG_FREE(msg);
+ m_reset_data_xfer_timers(sscop);
+ MAAL_ERROR(sscop, 'Q', 0);
+ sscop_recover(sscop);
+}
+
+/*
+ * p 67: READY && POLL PDU
+ */
+static void
+sscop_ready_poll(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+ union seqno seqno;
+ u_int sn, nps;
+ struct SSCOP_MBUF_T *m;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+ seqno.sscop_null = MBUF_STRIP32(msg->m);
+
+ if((u_int)pdu.sscop_ns < sscop->vr_h) {
+ SSCOP_MSG_FREE(msg);
+ m_reset_data_xfer_timers(sscop);
+ MAAL_ERROR(sscop, 'Q', 0);
+ sscop_recover(sscop);
+ return;
+ }
+ nps = seqno.sscop_n;
+
+ if((u_int)pdu.sscop_ns > sscop->vr_mr)
+ sscop->vr_h = sscop->vr_mr;
+ else
+ sscop->vr_h = pdu.sscop_ns;
+
+ SSCOP_MSG_FREE(msg);
+
+ /* build stat pdu */
+ if((m = MBUF_ALLOC(sscop->maxstat * 4 + 12)) == NULL) {
+ FAILURE("sscop: cannot allocate STAT");
+ return;
+ }
+ sn = sscop->vr_r;
+
+ while(sn != sscop->vr_h) {
+ /* loop through burst we already have */
+ for(;;) {
+ if(sn >= sscop->vr_h) {
+ seqno.sscop_null = 0;
+ seqno.sscop_n = sn;
+ MBUF_APPEND32(m, seqno.sscop_null);
+ goto out;
+ }
+ if(QFIND(&sscop->rbuf, sn) == NULL)
+ break;
+ sn++;
+ }
+
+ /* start of a hole */
+ seqno.sscop_null = 0;
+ seqno.sscop_n = sn;
+ MBUF_APPEND32(m, seqno.sscop_null);
+ if(MBUF_LEN(m)/4 >= sscop->maxstat) {
+ send_stat(sscop, nps, m);
+ if((m = MBUF_ALLOC(sscop->maxstat * 4 + 12)) == NULL) {
+ FAILURE("sscop: cannot allocate STAT");
+ return;
+ }
+ seqno.sscop_null = 0;
+ seqno.sscop_n = sn;
+ MBUF_APPEND32(m, seqno.sscop_null);
+ }
+ do {
+ sn++;
+ } while(sn < sscop->vr_h && !QFIND(&sscop->rbuf, sn));
+ seqno.sscop_null = 0;
+ seqno.sscop_n = sn;
+ MBUF_APPEND32(m, seqno.sscop_null);
+ }
+ out:
+ send_stat(sscop, nps, m);
+}
+
+/*
+ * p 69: READY && USTAT PDU
+ * arg is msg (freed)
+ */
+static void
+sscop_ready_ustat(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+ union seqno nmr, sq1, sq2;
+ u_int cnt;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+ nmr.sscop_null = MBUF_STRIP32(msg->m);
+ sq2.sscop_null = MBUF_STRIP32(msg->m);
+ sq1.sscop_null = MBUF_STRIP32(msg->m);
+
+ SSCOP_MSG_FREE(msg);
+
+ cnt = sq1.sscop_n - sq2.sscop_n;
+
+ if((u_int)pdu.sscop_ns < sscop->vt_a || (u_int)pdu.sscop_ns >= sscop->vt_s) {
+ VERBERR(sscop, SSCOP_DBG_ERR, (sscop, sscop->aarg,
+ "USTAT: N(R) outside VT(A)...VT(S)-1: N(R)=%u VT(A)=%u "
+ "VT(S)=%u", (u_int)pdu.sscop_ns, sscop->vt_a, sscop->vt_s));
+ goto err_f;
+ }
+
+ /* Acknowledge all messages between VT(A) and N(R)-1. N(R) is the new
+ * next in sequence-SD-number of the receiver and means, it has all
+ * messages below N(R). Remove all message below N(R) from the
+ * transmission buffer. It may already be removed because of an
+ * earlier selective ACK in a STAT message.
+ */
+ while((msg = MSGQ_PEEK(&sscop->xbuf)) != NULL && msg->seqno < (u_int)pdu.sscop_ns) {
+ ASSERT(msg->seqno >= sscop->vt_a);
+ MSGQ_REMOVE(&sscop->xbuf, msg);
+ SSCOP_MSG_FREE(msg);
+ }
+
+ /* Update the in-sequence acknowledge and the send window */
+ sscop->vt_a = pdu.sscop_ns;
+ sscop->vt_ms = nmr.sscop_n;
+
+ /* check, that the range of requested re-transmissions is between
+ * the in-sequence-ack and the highest up-to-now transmitted SD
+ */
+ if(sq1.sscop_n >= sq2.sscop_n
+ || (u_int)sq1.sscop_n < sscop->vt_a
+ || (u_int)sq2.sscop_n >= sscop->vt_s) {
+ VERBERR(sscop, SSCOP_DBG_ERR, (sscop, sscop->aarg,
+ "USTAT: seq1 or seq2 outside VT(A)...VT(S)-1 or seq1>=seq2:"
+ " seq1=%u seq2=%u VT(A)=%u VT(S)=%u",
+ sq1.sscop_n, sq2.sscop_n, sscop->vt_a, sscop->vt_s));
+ goto err_f;
+ }
+
+ /*
+ * Retransmit all messages from seq1 to seq2-1
+ */
+ do {
+ /*
+ * The message may not be in the transmit buffer if it was
+ * already acked by a STAT. This means, the receiver is
+ * confused.
+ */
+ if((msg = QFIND(&sscop->xbuf, sq1.sscop_n)) == NULL) {
+ VERBERR(sscop, SSCOP_DBG_ERR, (sscop, sscop->aarg,
+ "USTAT: message %u not found in xmit buffer",
+ sq1.sscop_n));
+ goto err_f;
+ }
+
+ /*
+ * If it is not yet in the re-transmission queue, put it there
+ */
+ if(!msg->rexmit) {
+ msg->rexmit = 1;
+ sscop->rxq++;
+ sscop_signal(sscop, SIG_PDU_Q, msg);
+ }
+ sq1.sscop_n++;
+ } while(sq1.sscop_n != sq2.sscop_n);
+
+ /*
+ * report the re-transmission to the management
+ */
+ MAAL_ERROR(sscop, 'V', cnt);
+ return;
+
+ err_f:
+ m_reset_data_xfer_timers(sscop);
+ MAAL_ERROR(sscop, 'T', 0);
+ sscop_recover(sscop);
+}
+
+/*
+ * p 70: READY && STAT PDU
+ * arg is msg (freed).
+ */
+static void
+sscop_ready_stat(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+ union seqno nps, nmr;
+ u_int len, seq1, seq2, cnt;
+ struct sscop_msg *m;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+ nmr.sscop_null = MBUF_STRIP32(msg->m);
+ nps.sscop_null = MBUF_STRIP32(msg->m);
+
+ len = MBUF_LEN(msg->m) / 4;
+
+ if((u_int)nps.sscop_n < sscop->vt_pa
+ || (u_int)nps.sscop_n > sscop->vt_ps) {
+ SSCOP_MSG_FREE(msg);
+ m_reset_data_xfer_timers(sscop);
+ MAAL_ERROR(sscop, 'R', 0);
+ sscop_recover(sscop);
+ return;
+ }
+
+ if((u_int)pdu.sscop_ns < sscop->vt_a
+ || (u_int)pdu.sscop_ns > sscop->vt_s) {
+ /*
+ * The in-sequence acknowledge, i.e. the receivers's next
+ * expected in-sequence msg is outside the window between
+ * the transmitters in-sequence ack and highest seqno -
+ * the receiver seems to be confused.
+ */
+ VERBERR(sscop, SSCOP_DBG_ERR, (sscop, sscop->aarg,
+ "STAT: N(R) outside VT(A)...VT(S)-1: N(R)=%u VT(A)=%u "
+ "VT(S)=%u", (u_int)pdu.sscop_ns, sscop->vt_a, sscop->vt_s));
+ err_H:
+ SSCOP_MSG_FREE(msg);
+ m_reset_data_xfer_timers(sscop);
+ MAAL_ERROR(sscop, 'S', 0);
+ sscop_recover(sscop);
+ return;
+ }
+
+ /* Acknowledge all messages between VT(A) and N(R)-1. N(R) is the new
+ * next in sequence-SD-number of the receiver and means, it has all
+ * messages below N(R). Remove all message below N(R) from the
+ * transmission buffer. It may already be removed because of an
+ * earlier selective ACK in a STAT message.
+ */
+ while((m = MSGQ_PEEK(&sscop->xbuf)) != NULL
+ && m->seqno < (u_int)pdu.sscop_ns) {
+ ASSERT(m->seqno >= sscop->vt_a);
+ MSGQ_REMOVE(&sscop->xbuf, m);
+ SSCOP_MSG_FREE(m);
+ }
+
+ /*
+ * Update in-sequence ack, poll-ack and send window.
+ */
+ sscop->vt_a = pdu.sscop_ns;
+ sscop->vt_pa = nps.sscop_n;
+ sscop->vt_ms = nmr.sscop_n;
+
+ cnt = 0;
+ if(len > 1) {
+ seq1 = MBUF_GET32(msg->m);
+ len--;
+ if(seq1 >= sscop->vt_s) {
+ VERBERR(sscop, SSCOP_DBG_ERR, (sscop, sscop->aarg,
+ "STAT: seq1 >= VT(S): seq1=%u VT(S)=%u",
+ seq1, sscop->vt_s));
+ goto err_H;
+ }
+
+ for(;;) {
+ seq2 = MBUF_GET32(msg->m);
+ len--;
+ if(seq1 >= seq2 || seq2 > sscop->vt_s) {
+ VERBERR(sscop, SSCOP_DBG_ERR, (sscop,
+ sscop->aarg, "STAT: seq1 >= seq2 or "
+ "seq2 > VT(S): seq1=%u seq2=%u VT(S)=%u",
+ seq1, seq2, sscop->vt_s));
+ goto err_H;
+ }
+
+ do {
+ /*
+ * The receiver requests the re-transmission
+ * of some message, but has acknowledged it
+ * already in an earlier STAT (it isn't in the
+ * transmitt buffer anymore).
+ */
+ if((m = QFIND(&sscop->xbuf, seq1)) == NULL) {
+ VERBERR(sscop, SSCOP_DBG_ERR,
+ (sscop, sscop->aarg, "STAT: message"
+ " %u not found in xmit buffer",
+ seq1));
+ goto err_H;
+ }
+ if(m->poll_seqno < (u_int)nps.sscop_n
+ && (u_int)nps.sscop_n <= sscop->vt_ps)
+ if(!m->rexmit) {
+ m->rexmit = 1;
+ sscop->rxq++;
+ cnt++;
+ sscop_signal(sscop, SIG_PDU_Q, msg);
+ }
+ } while(++seq1 < seq2);
+
+ if(len == 0)
+ break;
+
+ seq2 = MBUF_GET32(msg->m);
+ len--;
+
+ if(seq1 >= seq2 || seq2 > sscop->vt_s) {
+ VERBERR(sscop, SSCOP_DBG_ERR, (sscop,
+ sscop->aarg, "STAT: seq1 >= seq2 or "
+ "seq2 > VT(S): seq1=%u seq2=%u VT(S)=%u",
+ seq1, seq2, sscop->vt_s));
+ goto err_H;
+ }
+
+ /* OK now the sucessful transmitted messages. Note, that
+ * some messages may already be out of the buffer because
+ * of earlier STATS */
+ do {
+ if(sscop->clear_buffers) {
+ if((m = QFIND(&sscop->xbuf, seq1)) != NULL) {
+ MSGQ_REMOVE(&sscop->xbuf, m);
+ SSCOP_MSG_FREE(m);
+ }
+ }
+ } while(++seq1 != seq2);
+
+ if(len == 0)
+ break;
+ }
+ MAAL_ERROR(sscop, 'V', cnt);
+ }
+ SSCOP_MSG_FREE(msg);
+
+ /* label L: */
+ if(sscop->vt_s >= sscop->vt_ms) {
+ /*
+ * The receiver has closed the window: report to management
+ */
+ if(sscop->credit) {
+ sscop->credit = 0;
+ MAAL_ERROR(sscop, 'W', 0);
+ }
+ } else if(!sscop->credit) {
+ /*
+ * The window was forcefully closed above, but
+ * now re-opened. Report to management.
+ */
+ sscop->credit = 1;
+ MAAL_ERROR(sscop, 'X', 0);
+ }
+
+ if(TIMER_ISACT(sscop, poll)) {
+ TIMER_RESTART(sscop, nr);
+ } else if(!TIMER_ISACT(sscop, idle)) {
+ TIMER_STOP(sscop, ka);
+ TIMER_STOP(sscop, nr);
+ TIMER_RESTART(sscop, idle);
+ }
+}
+
+/*
+ * P. 73: any state & UDATA_REQUEST
+ * arg is pdu (queued)
+ */
+static void
+sscop_udata_req(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MSGQ_APPEND(&sscop->uxq, msg);
+ sscop_signal(sscop, SIG_UPDU_Q, msg);
+}
+
+/*
+ * P. 73: any state & MDATA_REQUEST
+ * arg is pdu (queued)
+ */
+static void
+sscop_mdata_req(struct sscop *sscop, struct sscop_msg *msg)
+{
+ MSGQ_APPEND(&sscop->mxq, msg);
+ sscop_signal(sscop, SIG_MPDU_Q, msg);
+}
+
+/*
+ * P. 74: any state & UDATA queued
+ * no arg.
+ */
+static void
+sscop_upduq(struct sscop *sscop, struct sscop_msg *unused __unused)
+{
+ struct sscop_msg *msg;
+
+ if(sscop->ll_busy)
+ return;
+ while((msg = MSGQ_GET(&sscop->uxq)) != NULL) {
+ send_ud(sscop, msg->m);
+ msg->m = NULL;
+ SSCOP_MSG_FREE(msg);
+ }
+}
+
+/*
+ * P. 74: any state & MDATA queued
+ * no arg.
+ */
+static void
+sscop_mpduq(struct sscop *sscop, struct sscop_msg *unused __unused)
+{
+ struct sscop_msg *msg;
+
+ if(sscop->ll_busy)
+ return;
+ while((msg = MSGQ_GET(&sscop->mxq)) != NULL) {
+ send_md(sscop, msg->m);
+ msg->m = NULL;
+ SSCOP_MSG_FREE(msg);
+ }
+}
+
+/*
+ * p 73: MD PDU
+ * arg is PDU
+ */
+static void
+sscop_md(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+
+ MBUF_UNPAD(msg->m, pdu.sscop_pl);
+
+ MAAL_DATA(sscop, msg->m);
+ msg->m = NULL;
+ SSCOP_MSG_FREE(msg);
+}
+
+/*
+ * p 73: UD PDU
+ * arg is PDU
+ */
+static void
+sscop_ud(struct sscop *sscop, struct sscop_msg *msg)
+{
+ union pdu pdu;
+
+ pdu.sscop_null = MBUF_STRIP32(msg->m);
+
+ MBUF_UNPAD(msg->m, pdu.sscop_pl);
+
+ AAL_DATA(sscop, SSCOP_UDATA_indication, msg->m, 0);
+ msg->m = NULL;
+ SSCOP_MSG_FREE(msg);
+}
+
+
+/*
+ * p 33: IDLE & RETRIEVE
+ * p 39: IN_PEND & RETRIEVE
+ * p 42: OUT_DIS_PEND & RETRIEVE
+ * p 48: IN_RESYNC_PEND & RETRIEVE
+ * p 53: REC_PEND & RETRIEVE
+ * p 58: IN_REC_PEND & RETRIEVE
+ */
+static void
+sscop_retrieve(struct sscop *sscop, struct sscop_msg *msg)
+{
+ m_data_retrieval(sscop, msg->rexmit);
+ SSCOP_MSG_FREE(msg);
+}
+
+/************************************************************/
+/*
+ * GENERAL EVENT HANDLING
+ */
+
+/*
+ * State/event matrix.
+ *
+ * Entries marked with Z are not specified in Q.2110, but are added for
+ * the sake of stability.
+ */
+static struct {
+ void (*func)(struct sscop *, struct sscop_msg *);
+ int (*cond)(struct sscop *);
+} state_matrix[SSCOP_NSTATES][SIG_NUM] = {
+ /* SSCOP_IDLE */ {
+ /* SIG_BGN */ { sscop_idle_bgn, NULL },
+ /* SIG_BGAK */ { sscop_idle_bgak, NULL },
+ /* SIG_END */ { sscop_idle_end, NULL },
+ /* SIG_ENDAK */ { sscop_ignore_pdu, NULL },
+ /* SIG_RS */ { sscop_idle_rs, NULL },
+ /* SIG_RSAK */ { sscop_idle_rsak, NULL },
+ /* SIG_BGREJ */ { sscop_idle_bgrej, NULL },
+ /* SIG_SD */ { sscop_idle_sd, NULL },
+ /* SIG_ER */ { sscop_idle_er, NULL },
+ /* SIG_POLL */ { sscop_idle_poll, NULL },
+ /* SIG_STAT */ { sscop_idle_stat, NULL },
+ /* SIG_USTAT */ { sscop_idle_ustat, NULL },
+ /* SIG_UD */ { sscop_ud, NULL },
+ /* SIG_MD */ { sscop_md, NULL },
+ /* SIG_ERAK */ { sscop_idle_erak, NULL },
+ /* SIG_T_CC */ { NULL, NULL },
+ /* SIG_T_POLL */ { NULL, NULL },
+ /* SIG_T_KA */ { NULL, NULL },
+ /* SIG_T_NR */ { NULL, NULL },
+ /* SIG_T_IDLE */ { NULL, NULL },
+ /* SIG_PDU_Q */ { sscop_flush_pduq, NULL },
+ /* SIG_USER_DATA */ { NULL, NULL },
+ /* SIG_ESTAB_REQ */ { sscop_idle_establish_req, NULL },
+ /* SIG_ESTAB_RESP */ { NULL, NULL },
+ /* SIG_RELEASE_REQ */ { NULL, NULL },
+ /* SIG_RECOVER */ { NULL, NULL },
+ /* SIG_SYNC_REQ */ { NULL, NULL },
+ /* SIG_SYNC_RESP */ { NULL, NULL },
+ /* SIG_UDATA */ { sscop_udata_req, NULL },
+ /* SIG_MDATA */ { sscop_mdata_req, NULL },
+ /* SIG_UPDU_Q */ { sscop_upduq, NULL },
+ /* SIG_MPDU_Q */ { sscop_mpduq, NULL },
+ /* SIG_RETRIEVE */ { sscop_retrieve, NULL },
+ },
+ /* SSCOP_OUT_PEND */ {
+ /* SIG_BGN */ { sscop_outpend_bgn, NULL },
+ /* SIG_BGAK */ { sscop_outpend_bgak, NULL },
+ /* SIG_END */ { sscop_ignore_pdu, NULL },
+ /* SIG_ENDAK */ { sscop_ignore_pdu, NULL },
+ /* SIG_RS */ { sscop_ignore_pdu, NULL },
+ /* SIG_RSAK */ { sscop_ignore_pdu, NULL },
+ /* SIG_BGREJ */ { sscop_outpend_bgrej, NULL },
+ /* SIG_SD */ { sscop_ignore_pdu, NULL },
+ /* SIG_ER */ { sscop_ignore_pdu, NULL },
+ /* SIG_POLL */ { sscop_ignore_pdu, NULL },
+ /* SIG_STAT */ { sscop_ignore_pdu, NULL },
+ /* SIG_USTAT */ { sscop_ignore_pdu, NULL },
+ /* SIG_UD */ { sscop_ud, NULL },
+ /* SIG_MD */ { sscop_md, NULL },
+ /* SIG_ERAK */ { sscop_ignore_pdu, NULL },
+ /* SIG_T_CC */ { sscop_outpend_tcc, NULL },
+ /* SIG_T_POLL */ { NULL, NULL },
+ /* SIG_T_KA */ { NULL, NULL },
+ /* SIG_T_NR */ { NULL, NULL },
+ /* SIG_T_IDLE */ { NULL, NULL },
+ /* SIG_PDU_Q */ { sscop_flush_pduq, NULL },
+ /* SIG_USER_DATA */ { NULL, NULL },
+ /* SIG_ESTAB_REQ */ { NULL, NULL },
+ /* SIG_ESTAB_RESP */ { NULL, NULL },
+ /* SIG_RELEASE_REQ */ { sscop_outpend_release_req, NULL },
+ /* SIG_RECOVER */ { NULL, NULL },
+ /* SIG_SYNC_REQ */ { NULL, NULL },
+ /* SIG_SYNC_RESP */ { NULL, NULL },
+ /* SIG_UDATA */ { sscop_udata_req, NULL },
+ /* SIG_MDATA */ { sscop_mdata_req, NULL },
+ /* SIG_UPDU_Q */ { sscop_upduq, NULL },
+ /* SIG_MPDU_Q */ { sscop_mpduq, NULL },
+ /* SIG_RETRIEVE */ { NULL, NULL },
+ },
+ /* SSCOP_IN_PEND */ {
+ /* SIG_BGN */ { sscop_inpend_bgn, NULL },
+ /* SIG_BGAK */ { sscop_inpend_bgak, NULL },
+ /* SIG_END */ { sscop_inpend_end, NULL },
+ /* SIG_ENDAK */ { sscop_inpend_endak, NULL },
+ /* SIG_RS */ { sscop_inpend_rs, NULL },
+ /* SIG_RSAK */ { sscop_inpend_rsak, NULL },
+ /* SIG_BGREJ */ { sscop_inpend_bgrej, NULL },
+ /* SIG_SD */ { sscop_inpend_sd, NULL },
+ /* SIG_ER */ { sscop_inpend_er, NULL },
+ /* SIG_POLL */ { sscop_inpend_poll, NULL },
+ /* SIG_STAT */ { sscop_inpend_stat, NULL },
+ /* SIG_USTAT */ { sscop_inpend_ustat, NULL },
+ /* SIG_UD */ { sscop_ud, NULL },
+ /* SIG_MD */ { sscop_md, NULL },
+ /* SIG_ERAK */ { sscop_inpend_erak, NULL },
+ /* SIG_T_CC */ { NULL, NULL },
+ /* SIG_T_POLL */ { NULL, NULL },
+ /* SIG_T_KA */ { NULL, NULL },
+ /* SIG_T_NR */ { NULL, NULL },
+ /* SIG_T_IDLE */ { NULL, NULL },
+ /* SIG_PDU_Q */ { sscop_flush_pduq, NULL },
+ /* SIG_USER_DATA */ { NULL, NULL },
+ /* SIG_ESTAB_REQ */ { NULL, NULL },
+ /* SIG_ESTAB_RESP */ { sscop_inpend_establish_resp, NULL },
+ /* SIG_RELEASE_REQ */ { sscop_inpend_release_req, NULL },
+ /* SIG_RECOVER */ { NULL, NULL },
+ /* SIG_SYNC_REQ */ { NULL, NULL },
+ /* SIG_SYNC_RESP */ { NULL, NULL },
+ /* SIG_UDATA */ { sscop_udata_req, NULL },
+ /* SIG_MDATA */ { sscop_mdata_req, NULL },
+ /* SIG_UPDU_Q */ { sscop_upduq, NULL },
+ /* SIG_MPDU_Q */ { sscop_mpduq, NULL },
+ /* SIG_RETRIEVE */ { sscop_retrieve, NULL },
+ },
+ /* SSCOP_OUT_DIS_PEND */ {
+ /* SIG_BGN */ { sscop_outdis_bgn, NULL },
+ /* SIG_BGAK */ { sscop_ignore_pdu, NULL },
+ /* SIG_END */ { sscop_outdis_end, NULL },
+ /* SIG_ENDAK */ { sscop_outdis_endak, NULL },
+ /* SIG_RS */ { sscop_ignore_pdu, NULL },
+ /* SIG_RSAK */ { sscop_ignore_pdu, NULL },
+ /* SIG_BGREJ */ { sscop_outdis_endak, NULL },
+ /* SIG_SD */ { sscop_ignore_pdu, NULL },
+ /* SIG_ER */ { sscop_ignore_pdu, NULL },
+ /* SIG_POLL */ { sscop_ignore_pdu, NULL },
+ /* SIG_STAT */ { sscop_ignore_pdu, NULL },
+ /* SIG_USTAT */ { sscop_ignore_pdu, NULL },
+ /* SIG_UD */ { sscop_ud, NULL },
+ /* SIG_MD */ { sscop_md, NULL },
+ /* SIG_ERAK */ { sscop_ignore_pdu, NULL },
+ /* SIG_T_CC */ { sscop_outdis_cc, NULL },
+ /* SIG_T_POLL */ { NULL, NULL },
+ /* SIG_T_KA */ { NULL, NULL },
+ /* SIG_T_NR */ { NULL, NULL },
+ /* SIG_T_IDLE */ { NULL, NULL },
+ /* SIG_PDU_Q */ { sscop_flush_pduq, NULL },
+ /* SIG_USER_DATA */ { NULL, NULL },
+ /* SIG_ESTAB_REQ */ { sscop_outdis_establish_req, NULL },
+ /* SIG_ESTAB_RESP */ { NULL, NULL },
+ /* SIG_RELEASE_REQ */ { NULL, NULL },
+ /* SIG_RECOVER */ { NULL, NULL },
+ /* SIG_SYNC_REQ */ { NULL, NULL },
+ /* SIG_SYNC_RESP */ { NULL, NULL },
+ /* SIG_UDATA */ { sscop_udata_req, NULL },
+ /* SIG_MDATA */ { sscop_mdata_req, NULL },
+ /* SIG_UPDU_Q */ { sscop_upduq, NULL },
+ /* SIG_MPDU_Q */ { sscop_mpduq, NULL },
+ /* SIG_RETRIEVE */ { sscop_retrieve, NULL },
+ },
+ /* SSCOP_OUT_RESYNC_PEND */ {
+ /* SIG_BGN */ { sscop_outsync_bgn, NULL },
+ /* SIG_BGAK */ { sscop_ignore_pdu, NULL },
+ /* SIG_END */ { sscop_outsync_end, NULL },
+ /* SIG_ENDAK */ { sscop_outsync_endak, NULL },
+ /* SIG_RS */ { sscop_outsync_rs, NULL },
+ /* SIG_RSAK */ { sscop_outsync_rsak, NULL },
+ /* SIG_BGREJ */ { sscop_outsync_bgrej, NULL },
+ /* SIG_SD */ { sscop_ignore_pdu, NULL },
+ /* SIG_ER */ { sscop_ignore_pdu, NULL },
+ /* SIG_POLL */ { sscop_ignore_pdu, NULL },
+ /* SIG_STAT */ { sscop_ignore_pdu, NULL },
+ /* SIG_USTAT */ { sscop_ignore_pdu, NULL },
+ /* SIG_UD */ { sscop_ud, NULL },
+ /* SIG_MD */ { sscop_md, NULL },
+ /* SIG_ERAK */ { sscop_ignore_pdu, NULL },
+ /* SIG_T_CC */ { sscop_outsync_cc, NULL },
+ /* SIG_T_POLL */ { NULL, NULL },
+ /* SIG_T_KA */ { NULL, NULL },
+ /* SIG_T_NR */ { NULL, NULL },
+ /* SIG_T_IDLE */ { NULL, NULL },
+ /* SIG_PDU_Q */ { sscop_flush_pduq, NULL },
+ /* SIG_USER_DATA */ { NULL, NULL },
+ /* SIG_ESTAB_REQ */ { NULL, NULL },
+ /* SIG_ESTAB_RESP */ { NULL, NULL },
+ /* SIG_RELEASE_REQ */ { sscop_outsync_release_req, NULL },
+ /* SIG_RECOVER */ { NULL, NULL },
+ /* SIG_SYNC_REQ */ { NULL, NULL },
+ /* SIG_SYNC_RESP */ { NULL, NULL },
+ /* SIG_UDATA */ { sscop_udata_req, NULL },
+ /* SIG_MDATA */ { sscop_mdata_req, NULL },
+ /* SIG_UPDU_Q */ { sscop_upduq, NULL },
+ /* SIG_MPDU_Q */ { sscop_mpduq, NULL },
+ /* SIG_RETRIEVE */ { NULL, NULL },
+ },
+ /* SSCOP_IN_RESYNC_PEND */ {
+ /* SIG_BGN */ { sscop_insync_bgn, NULL },
+ /* SIG_BGAK */ { sscop_insync_bgak, NULL },
+ /* SIG_END */ { sscop_insync_end, NULL },
+ /* SIG_ENDAK */ { sscop_insync_endak, NULL },
+ /* SIG_RS */ { sscop_insync_rs, NULL },
+ /* SIG_RSAK */ { sscop_insync_rsak, NULL },
+ /* SIG_BGREJ */ { sscop_insync_bgrej, NULL },
+ /* SIG_SD */ { sscop_insync_sd, NULL },
+ /* SIG_ER */ { sscop_insync_er, NULL },
+ /* SIG_POLL */ { sscop_insync_poll, NULL },
+ /* SIG_STAT */ { sscop_insync_stat, NULL },
+ /* SIG_USTAT */ { sscop_insync_ustat, NULL },
+ /* SIG_UD */ { sscop_ud, NULL },
+ /* SIG_MD */ { sscop_md, NULL },
+ /* SIG_ERAK */ { sscop_insync_erak, NULL },
+ /* SIG_T_CC */ { NULL, NULL },
+ /* SIG_T_POLL */ { NULL, NULL },
+ /* SIG_T_KA */ { NULL, NULL },
+ /* SIG_T_NR */ { NULL, NULL },
+ /* SIG_T_IDLE */ { NULL, NULL },
+ /* SIG_PDU_Q */ { sscop_flush_pduq, NULL },
+ /* SIG_USER_DATA */ { NULL, NULL },
+ /* SIG_ESTAB_REQ */ { NULL, NULL },
+ /* SIG_ESTAB_RESP */ { NULL, NULL },
+ /* SIG_RELEASE_REQ */ { sscop_insync_release_req, NULL },
+ /* SIG_RECOVER */ { NULL, NULL },
+ /* SIG_SYNC_REQ */ { NULL, NULL },
+ /* SIG_SYNC_RESP */ { sscop_insync_sync_resp, NULL },
+ /* SIG_UDATA */ { sscop_udata_req, NULL },
+ /* SIG_MDATA */ { sscop_mdata_req, NULL },
+ /* SIG_UPDU_Q */ { sscop_upduq, NULL },
+ /* SIG_MPDU_Q */ { sscop_mpduq, NULL },
+ /* SIG_RETRIEVE */ { sscop_retrieve, NULL },
+ },
+ /* SSCOP_OUT_REC_PEND */ {
+ /* SIG_BGN */ { sscop_outrec_bgn, NULL },
+ /* SIG_BGAK */ { sscop_outrec_bgak, NULL },
+ /* SIG_END */ { sscop_outrec_end, NULL },
+ /* SIG_ENDAK */ { sscop_outrec_endak, NULL },
+ /* SIG_RS */ { sscop_outrec_rs, NULL },
+ /* SIG_RSAK */ { sscop_outrec_rsak, NULL },
+ /* SIG_BGREJ */ { sscop_outrec_bgrej, NULL },
+ /* SIG_SD */ { sscop_ignore_pdu, NULL },
+ /* SIG_ER */ { sscop_outrec_er, NULL },
+ /* SIG_POLL */ { sscop_ignore_pdu, NULL },
+ /* SIG_STAT */ { sscop_ignore_pdu, NULL },
+ /* SIG_USTAT */ { sscop_ignore_pdu, NULL },
+ /* SIG_UD */ { sscop_ud, NULL },
+ /* SIG_MD */ { sscop_md, NULL },
+ /* SIG_ERAK */ { sscop_outrec_erak, NULL },
+ /* SIG_T_CC */ { sscop_outrec_cc, NULL },
+ /* SIG_T_POLL */ { NULL, NULL },
+ /* SIG_T_KA */ { NULL, NULL },
+ /* SIG_T_NR */ { NULL, NULL },
+ /* SIG_T_IDLE */ { NULL, NULL },
+ /* SIG_PDU_Q */ { sscop_outrec_pduq, NULL },
+ /* SIG_USER_DATA */ { sscop_outrec_userdata, NULL },
+ /* SIG_ESTAB_REQ */ { NULL, NULL },
+ /* SIG_ESTAB_RESP */ { NULL, NULL },
+ /* SIG_RELEASE_REQ */ { sscop_outrec_release_req, NULL },
+ /* SIG_RECOVER */ { NULL, NULL },
+ /* SIG_SYNC_REQ */ { sscop_outrec_sync_req, NULL },
+ /* SIG_SYNC_RESP */ { NULL, NULL },
+ /* SIG_UDATA */ { sscop_udata_req, NULL },
+ /* SIG_MDATA */ { sscop_mdata_req, NULL },
+ /* SIG_UPDU_Q */ { sscop_upduq, NULL },
+ /* SIG_MPDU_Q */ { sscop_mpduq, NULL },
+ /* SIG_RETRIEVE */ { NULL, NULL },
+ },
+ /* SSCOP_REC_PEND */ {
+ /* SIG_BGN */ { sscop_rec_bgn, NULL },
+ /* SIG_BGAK */ { sscop_rec_bgak, NULL },
+ /* SIG_END */ { sscop_rec_end, NULL },
+ /* SIG_ENDAK */ { sscop_rec_endak, NULL },
+ /* SIG_RS */ { sscop_rec_rs, NULL },
+ /* SIG_RSAK */ { sscop_rec_rsak, NULL },
+ /* SIG_BGREJ */ { sscop_rec_bgrej, NULL },
+ /* SIG_SD */ { sscop_ignore_pdu, NULL },
+ /* SIG_ER */ { sscop_rec_er, NULL },
+ /* SIG_POLL */ { sscop_ignore_pdu, NULL },
+ /* SIG_STAT */ { sscop_rec_stat, NULL },
+ /* SIG_USTAT */ { sscop_rec_ustat, NULL },
+ /* SIG_UD */ { sscop_ud, NULL },
+ /* SIG_MD */ { sscop_md, NULL },
+ /* SIG_ERAK */ { sscop_ignore_pdu, NULL },
+ /* SIG_T_CC */ { NULL, NULL },
+ /* SIG_T_POLL */ { NULL, NULL },
+ /* SIG_T_KA */ { NULL, NULL },
+ /* SIG_T_NR */ { NULL, NULL },
+ /* SIG_T_IDLE */ { NULL, NULL },
+ /* SIG_PDU_Q */ { sscop_rec_pduq, NULL },
+ /* SIG_USER_DATA */ { NULL, NULL },
+ /* SIG_ESTAB_REQ */ { NULL, NULL },
+ /* SIG_ESTAB_RESP */ { NULL, NULL },
+ /* SIG_RELEASE_REQ */ { sscop_rec_release_req, NULL },
+ /* SIG_RECOVER */ { sscop_rec_recover, NULL },
+ /* SIG_SYNC_REQ */ { sscop_rec_sync_req, NULL },
+ /* SIG_SYNC_RESP */ { NULL, NULL },
+ /* SIG_UDATA */ { sscop_udata_req, NULL },
+ /* SIG_MDATA */ { sscop_mdata_req, NULL },
+ /* SIG_UPDU_Q */ { sscop_upduq, NULL },
+ /* SIG_MPDU_Q */ { sscop_mpduq, NULL },
+ /* SIG_RETRIEVE */ { sscop_retrieve, NULL },
+ },
+ /* SSCOP_IN_REC_PEND */ {
+ /* SIG_BGN */ { sscop_inrec_bgn, NULL },
+ /* SIG_BGAK */ { sscop_inrec_bgak, NULL },
+ /* SIG_END */ { sscop_inrec_end, NULL },
+ /* SIG_ENDAK */ { sscop_inrec_endak, NULL },
+ /* SIG_RS */ { sscop_inrec_rs, NULL },
+ /* SIG_RSAK */ { sscop_inrec_rsak, NULL },
+ /* SIG_BGREJ */ { sscop_inrec_bgrej, NULL },
+ /* SIG_SD */ { sscop_inrec_sd, NULL },
+ /* SIG_ER */ { sscop_inrec_er, NULL },
+ /* SIG_POLL */ { sscop_inrec_poll, NULL },
+ /* SIG_STAT */ { sscop_inrec_stat, NULL },
+ /* SIG_USTAT */ { sscop_inrec_ustat, NULL },
+ /* SIG_UD */ { sscop_ud, NULL },
+ /* SIG_MD */ { sscop_md, NULL },
+ /* SIG_ERAK */ { sscop_inrec_erak, NULL },
+ /* SIG_T_CC */ { NULL, NULL },
+ /* SIG_T_POLL */ { NULL, NULL },
+ /* SIG_T_KA */ { NULL, NULL },
+ /* SIG_T_NR */ { NULL, NULL },
+ /* SIG_T_IDLE */ { NULL, NULL },
+ /* SIG_PDU_Q */ { sscop_inrec_pduq, NULL },
+ /* SIG_USER_DATA */ { NULL, NULL },
+ /* SIG_ESTAB_REQ */ { NULL, NULL },
+ /* SIG_ESTAB_RESP */ { NULL, NULL },
+ /* SIG_RELEASE_REQ */ { sscop_inrec_release_req, NULL },
+ /* SIG_RECOVER */ { sscop_inrec_recover, NULL },
+ /* SIG_SYNC_REQ */ { sscop_inrec_sync_req, NULL },
+ /* SIG_SYNC_RESP */ { NULL, NULL },
+ /* SIG_UDATA */ { sscop_udata_req, NULL },
+ /* SIG_MDATA */ { sscop_mdata_req, NULL },
+ /* SIG_UPDU_Q */ { sscop_upduq, NULL },
+ /* SIG_MPDU_Q */ { sscop_mpduq, NULL },
+ /* SIG_RETRIEVE */ { sscop_retrieve, NULL },
+ },
+ /* SSCOP_READY */ {
+ /* SIG_BGN */ { sscop_ready_bgn, NULL },
+ /* SIG_BGAK */ { sscop_ignore_pdu, NULL },
+ /* SIG_END */ { sscop_ready_end, NULL },
+ /* SIG_ENDAK */ { sscop_ready_endak, NULL },
+ /* SIG_RS */ { sscop_ready_rs, NULL },
+ /* SIG_RSAK */ { sscop_ignore_pdu, NULL },
+ /* SIG_BGREJ */ { sscop_ready_bgrej, NULL },
+ /* SIG_SD */ { sscop_ready_sd, NULL },
+ /* SIG_ER */ { sscop_ready_er, NULL },
+ /* SIG_POLL */ { sscop_ready_poll, NULL },
+ /* SIG_STAT */ { sscop_ready_stat, NULL },
+ /* SIG_USTAT */ { sscop_ready_ustat, NULL },
+ /* SIG_UD */ { sscop_ud, NULL },
+ /* SIG_MD */ { sscop_md, NULL },
+ /* SIG_ERAK */ { sscop_ignore_pdu, NULL },
+ /* SIG_T_CC */ { NULL, NULL },
+ /* SIG_T_POLL */ { sscop_ready_tpoll, NULL },
+ /* SIG_T_KA */ { sscop_ready_tka, NULL },
+ /* SIG_T_NR */ { sscop_ready_nr, NULL },
+ /* SIG_T_IDLE */ { sscop_ready_tidle, NULL },
+ /* SIG_PDU_Q */ { sscop_ready_pduq, c_ready_pduq },
+ /* SIG_USER_DATA */ { sscop_ready_userdata, NULL },
+ /* SIG_ESTAB_REQ */ { NULL, NULL },
+ /* SIG_ESTAB_RESP */ { NULL, NULL },
+ /* SIG_RELEASE_REQ */ { sscop_ready_release_req, NULL },
+ /* SIG_RECOVER */ { NULL, NULL },
+ /* SIG_SYNC_REQ */ { sscop_ready_sync_req, NULL },
+ /* SIG_SYNC_RESP */ { NULL, NULL },
+ /* SIG_UDATA */ { sscop_udata_req, NULL },
+ /* SIG_MDATA */ { sscop_mdata_req, NULL },
+ /* SIG_UPDU_Q */ { sscop_upduq, NULL },
+ /* SIG_MPDU_Q */ { sscop_mpduq, NULL },
+ /* SIG_RETRIEVE */ { NULL, NULL },
+ }
+};
+
+/*
+ * Try to execute a signal. It is executed if
+ * - it is illegal (in this case it is effectively ignored)
+ * - it has no condition
+ * - its condition is true
+ * If it has a condition and that is false, the function does nothing and
+ * returns 0.
+ * If the signal gets executed, the signal function is responsible to release
+ * the message (if any).
+ */
+static int
+sig_exec(struct sscop *sscop, u_int sig, struct sscop_msg *msg)
+{
+ void (*func)(struct sscop *, struct sscop_msg *);
+ int (*cond)(struct sscop *);
+
+ func = state_matrix[sscop->state][sig].func;
+ cond = state_matrix[sscop->state][sig].cond;
+
+ if(func == NULL) {
+ VERBOSE(sscop, SSCOP_DBG_BUG, (sscop, sscop->aarg,
+ "no handler for %s in state %s - ignored",
+ events[sig], states[sscop->state]));
+ SSCOP_MSG_FREE(msg);
+ return 1;
+ }
+ if(cond == NULL || (*cond)(sscop)) {
+ VERBOSE(sscop, SSCOP_DBG_EXEC, (sscop, sscop->aarg,
+ "executing %s in %s", events[sig],
+ states[sscop->state]));
+ (*func)(sscop, msg);
+ return 1;
+ }
+ VERBOSE(sscop, SSCOP_DBG_EXEC, (sscop, sscop->aarg,
+ "delaying %s in %s", events[sig],
+ states[sscop->state]));
+
+ return 0;
+}
+
+/*
+ * Deliver a signal to the given sscop
+ * If it is delivered from inside a signal handler - queue it. If not,
+ * execute it. After execution loop through the queue and execute all
+ * pending signals. Signals, that cannot be executed because of entry
+ * conditions are skipped.
+ */
+static void
+sscop_signal(struct sscop *sscop, u_int sig, struct sscop_msg *msg)
+{
+ struct sscop_sig *s;
+
+ VERBOSE(sscop, SSCOP_DBG_INSIG, (sscop, sscop->aarg,
+ "got signal %s in state %s%s", events[sig],
+ states[sscop->state], sscop->in_sig ? " -- queuing" : ""));
+
+ SIG_ALLOC(s);
+ if(s == NULL) {
+ FAILURE("sscop: cannot allocate signal");
+ SSCOP_MSG_FREE(msg);
+ return;
+ }
+ s->sig = sig;
+ s->msg = msg;
+ SIGQ_APPEND(&sscop->sigs, s);
+
+ if(!sscop->in_sig)
+ handle_sigs(sscop);
+}
+
+/*
+ * Loop through the signal queue until we can't execute any signals.
+ */
+static void
+handle_sigs(struct sscop *sscop)
+{
+ struct sscop_sig *s;
+ sscop_sigq_head_t dsigs, q;
+ int exec;
+
+ sscop->in_sig++;
+
+ /*
+ * Copy the current signal queue to the local one and empty
+ * the signal queue. Then loop through the signals. After one
+ * pass we have a list of delayed signals because of entry
+ * conditions and a new list of signals. Merge them. Repeat until
+ * the signal queue is either empty or contains only delayed signals.
+ */
+ SIGQ_INIT(&q);
+ SIGQ_INIT(&dsigs);
+ do {
+ exec = 0;
+
+ /*
+ * Copy signal list and make sscop list empty
+ */
+ SIGQ_MOVE(&sscop->sigs, &q);
+
+ /*
+ * Loop through the list
+ */
+ while((s = SIGQ_GET(&q)) != NULL) {
+ if(sig_exec(sscop, s->sig, s->msg)) {
+ exec = 1;
+ SIG_FREE(s);
+ } else {
+ SIGQ_APPEND(&dsigs, s);
+ }
+ }
+
+ /*
+ * Merge lists by inserting delayed signals in front of
+ * the signal list. preserving the order.
+ */
+ SIGQ_PREPEND(&dsigs, &sscop->sigs);
+ } while(exec);
+ sscop->in_sig--;
+}
+
+/*
+ * Save a signal that should be executed only if state changes.
+ */
+static void
+sscop_save_signal(struct sscop *sscop, u_int sig, struct sscop_msg *msg)
+{
+ struct sscop_sig *s;
+
+ SIG_ALLOC(s);
+ if(s == NULL) {
+ FAILURE("sscop: cannot allocate signal");
+ SSCOP_MSG_FREE(msg);
+ return;
+ }
+ s->sig = sig;
+ s->msg = msg;
+ SIGQ_APPEND(&sscop->saved_sigs, s);
+}
+
+/*
+ * Set a new state. If signals are waiting for a state change - append them to
+ * the signal queue, so they get executed.
+ */
+static void
+sscop_set_state(struct sscop *sscop, u_int nstate)
+{
+ VERBOSE(sscop, SSCOP_DBG_STATE, (sscop, sscop->aarg,
+ "changing state from %s to %s",
+ states[sscop->state], states[nstate]));
+
+ sscop->state = nstate;
+ SIGQ_MOVE(&sscop->saved_sigs, &sscop->sigs);
+}
+
+void
+sscop_setdebug(struct sscop *sscop, u_int n)
+{
+ sscop->debug = n;
+}
+
+u_int
+sscop_getdebug(const struct sscop *sscop)
+{
+ return (sscop->debug);
+}
diff --git a/sys/contrib/ngatm/netnatm/saal/sscfu.h b/sys/contrib/ngatm/netnatm/saal/sscfu.h
new file mode 100644
index 0000000..f62e908
--- /dev/null
+++ b/sys/contrib/ngatm/netnatm/saal/sscfu.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 1996-2003
+ * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Hartmut Brandt <harti@freebsd.org>
+ *
+ * $Begemot: libunimsg/atm/saal/sscfu.h,v 1.3 2003/09/19 12:02:03 hbb Exp $
+ *
+ * Public include file for UNI SSCF
+ */
+#ifndef _NETNATM_SAAL_SSCFU_H_
+#define _NETNATM_SAAL_SSCFU_H_
+
+#include <sys/types.h>
+#include <netnatm/saal/sscopdef.h>
+#include <netnatm/saal/sscfudef.h>
+
+/*
+ * Define how a buffer looks like.
+ */
+#ifdef _KERNEL
+#ifdef __FreeBSD__
+#define SSCFU_MBUF_T mbuf
+#endif
+#else
+#define SSCFU_MBUF_T uni_msg
+#endif
+
+struct SSCFU_MBUF_T;
+struct sscfu;
+
+/* functions to be supplied by the SSCOP user */
+struct sscfu_funcs {
+ /* upper (SAAL) interface output */
+ void (*send_upper)(struct sscfu *, void *, enum saal_sig,
+ struct SSCFU_MBUF_T *);
+
+ /* lower (SSCOP) interface output */
+ void (*send_lower)(struct sscfu *, void *, enum sscop_aasig,
+ struct SSCFU_MBUF_T *, u_int);
+
+ /* function to move the SSCOP window */
+ void (*window)(struct sscfu *, void *, u_int);
+
+ /* debugging function */
+ void (*verbose)(struct sscfu *, void *, const char *, ...)
+ __printflike(3, 4);
+};
+
+/* Function defined by the SSCF-UNI code */
+
+/* allocate and initialize a new SSCF instance */
+struct sscfu *sscfu_create(void *, const struct sscfu_funcs *);
+
+/* destroy an SSCF instance and free all resources */
+void sscfu_destroy(struct sscfu *);
+
+/* reset the SSCF to the released state */
+void sscfu_reset(struct sscfu *);
+
+/* lower input interface (SSCOP signals) */
+void sscfu_input(struct sscfu *, enum sscop_aasig, struct SSCFU_MBUF_T *, u_int);
+
+/* upper input interface (SAAL) */
+int sscfu_saalsig(struct sscfu *, enum saal_sig, struct SSCFU_MBUF_T *);
+
+/* retrieve the current state */
+enum sscfu_state sscfu_getstate(const struct sscfu *);
+
+/* char'ify signals and states */
+const char *sscfu_signame(enum saal_sig);
+const char *sscfu_statename(enum sscfu_state);
+
+/* retrieve the default set of parameters for SSCOP */
+u_int sscfu_getdefparam(struct sscop_param *);
+
+/* get/set debugging flags */
+void sscfu_setdebug(struct sscfu *, u_int);
+u_int sscfu_getdebug(const struct sscfu *);
+
+#endif
diff --git a/sys/contrib/ngatm/netnatm/saal/sscfudef.h b/sys/contrib/ngatm/netnatm/saal/sscfudef.h
new file mode 100644
index 0000000..866e43e
--- /dev/null
+++ b/sys/contrib/ngatm/netnatm/saal/sscfudef.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 1996-2003
+ * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Hartmut Brandt <harti@freebsd.org>
+ *
+ * $Begemot: libunimsg/atm/saal/sscfudef.h,v 1.3 2003/09/19 12:02:03 hbb Exp $
+ *
+ * Definitions of UNI SSCF constants.
+ */
+#ifndef _NETNATM_SAAL_SSCFUDEF_H_
+#define _NETNATM_SAAL_SSCFUDEF_H_
+
+/*
+ * Signals at the upper boundary of the SSCF.
+ */
+enum saal_sig {
+ SAAL_ESTABLISH_request, /* U -> SAAL: (UU) */
+ SAAL_ESTABLISH_indication, /* SAAL -> U: (UU) */
+ SAAL_ESTABLISH_confirm, /* SAAL -> U: (UU) */
+ SAAL_RELEASE_request, /* U -> SAAL: (UU) */
+ SAAL_RELEASE_confirm, /* SAAL -> U: */
+ SAAL_RELEASE_indication, /* SAAL -> U: (UU) */
+ SAAL_DATA_request, /* U -> SAAL: (DATA) */
+ SAAL_DATA_indication, /* SAAL -> U: (DATA) */
+ SAAL_UDATA_request, /* U -> SAAL: (UDATA) */
+ SAAL_UDATA_indication, /* SAAL -> U: (UDATA) */
+};
+
+/*
+ * States of the SSCF
+ */
+enum sscfu_state {
+ SSCFU_RELEASED, /* 1/1 */
+ SSCFU_AWAITING_ESTABLISH, /* 2/2 */
+ SSCFU_AWAITING_RELEASE, /* 4/10 */
+ SSCFU_ESTABLISHED, /* 3/4 */
+ SSCFU_RESYNC, /* 2/5 */
+};
+
+/*
+ * Debugging flags
+ */
+enum {
+ SSCFU_DBG_LSIG = 0x01,
+ SSCFU_DBG_ERR = 0x02,
+ SSCFU_DBG_STATE = 0x04,
+ SSCFU_DBG_EXEC = 0x08,
+};
+
+#endif
diff --git a/sys/contrib/ngatm/netnatm/saal/sscfupriv.h b/sys/contrib/ngatm/netnatm/saal/sscfupriv.h
new file mode 100644
index 0000000..b807b4f
--- /dev/null
+++ b/sys/contrib/ngatm/netnatm/saal/sscfupriv.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1996-2003
+ * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Hartmut Brandt <harti@freebsd.org>
+ *
+ * $Begemot: libunimsg/atm/saal/sscfupriv.h,v 1.3 2003/09/19 12:02:03 hbb Exp $
+ *
+ * Private SSCF-UNI definitions.
+ */
+#ifdef _KERNEL
+#ifdef __FreeBSD__
+#include <netgraph/atm/sscfu/ng_sscfu_cust.h>
+#endif
+#else
+#include "sscfucust.h"
+#endif
+
+/*
+ * Structure for signal queueing.
+ */
+struct sscfu_sig {
+ sscfu_sigq_link_t link; /* link to next signal */
+ enum saal_sig sig; /* the signal */
+ struct SSCFU_MBUF_T *m; /* associated message */
+};
+
+struct sscfu {
+ enum sscfu_state state; /* SSCF state */
+ const struct sscfu_funcs *funcs; /* func vector */
+ void *aarg; /* user arg */
+ int inhand; /* need to queue signals */
+ sscfu_sigq_head_t sigs; /* signal queue */
+ u_int debug; /* debugging flags */
+};
+
+/*
+ * Debugging
+ */
+#ifdef SSCFU_DEBUG
+#define VERBOSE(S,M,F) if ((S)->debug & (M)) (S)->funcs->verbose F
+#else
+#define VERBOSE(S,M,F)
+#endif
diff --git a/sys/contrib/ngatm/netnatm/saal/sscop.h b/sys/contrib/ngatm/netnatm/saal/sscop.h
new file mode 100644
index 0000000..65965f5
--- /dev/null
+++ b/sys/contrib/ngatm/netnatm/saal/sscop.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 1996-2003
+ * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Hartmut Brandt <harti@freebsd.org>
+ *
+ * $Begemot: libunimsg/atm/saal/sscop.h,v 1.3 2003/09/19 12:02:03 hbb Exp $
+ *
+ * External interface to sscop.
+ */
+#ifndef _NETNATM_SAAL_SSCOP_H_
+#define _NETNATM_SAAL_SSCOP_H_
+
+#include <netnatm/saal/sscopdef.h>
+
+/*
+ * Define how a buffer looks like.
+ */
+#ifdef _KERNEL
+#ifdef __FreeBSD__
+#define SSCOP_MBUF_T mbuf
+#endif
+#else
+#define SSCOP_MBUF_T uni_msg
+#endif
+
+struct SSCOP_MBUF_T;
+struct sscop;
+
+/*
+ * Vector for user functions
+ */
+struct sscop_funcs {
+ /* management signal from SSCOP */
+ void (*send_manage)(struct sscop *, void *, enum sscop_maasig,
+ struct SSCOP_MBUF_T *, u_int, u_int);
+
+ /* AAL signal from SSCOP */
+ void (*send_upper)(struct sscop *, void *, enum sscop_aasig,
+ struct SSCOP_MBUF_T *, u_int);
+
+ /* send a PDU to the wire */
+ void (*send_lower)(struct sscop *, void *,
+ struct SSCOP_MBUF_T *);
+
+ /* print a message */
+ void (*verbose)(struct sscop *, void *, const char *, ...)
+ __printflike(3,4);
+
+#ifndef _KERNEL
+ /* start a timer */
+ void *(*start_timer)(struct sscop *, void *, u_int,
+ void (*)(void *));
+
+ /* stop a timer */
+ void (*stop_timer)(struct sscop *, void *, void *);
+#endif
+};
+
+/* Function defined by the SSCOP code */
+
+/* create a new SSCOP instance and initialize to default values */
+struct sscop *sscop_create(void *, const struct sscop_funcs *);
+
+/* destroy an SSCOP instance */
+void sscop_destroy(struct sscop *);
+
+/* get the current parameters of an SSCOP */
+void sscop_getparam(const struct sscop *, struct sscop_param *);
+
+/* set new parameters in an SSCOP */
+int sscop_setparam(struct sscop *, struct sscop_param *, u_int *);
+
+/* deliver an signal to the SSCOP */
+int sscop_aasig(struct sscop *, enum sscop_aasig, struct SSCOP_MBUF_T *, u_int);
+
+/* deliver an management signal to the SSCOP */
+int sscop_maasig(struct sscop *, enum sscop_maasig, struct SSCOP_MBUF_T *);
+
+/* SSCOP input function */
+void sscop_input(struct sscop *, struct SSCOP_MBUF_T *);
+
+/* Move the window by a given number of messages. Return the new window */
+u_int sscop_window(struct sscop *, u_int);
+
+/* declare the lower layer busy or not busy */
+u_int sscop_setbusy(struct sscop *, int);
+
+/* retrieve the state */
+enum sscop_state sscop_getstate(const struct sscop *);
+
+/* map signals to strings */
+const char *sscop_msigname(enum sscop_maasig);
+const char *sscop_signame(enum sscop_aasig);
+const char *sscop_statename(enum sscop_state);
+
+/* set/get debugging state */
+void sscop_setdebug(struct sscop *, u_int);
+u_int sscop_getdebug(const struct sscop *);
+
+/* reset the instance */
+void sscop_reset(struct sscop *);
+
+#endif
diff --git a/sys/contrib/ngatm/netnatm/saal/sscopdef.h b/sys/contrib/ngatm/netnatm/saal/sscopdef.h
new file mode 100644
index 0000000..09bd65c
--- /dev/null
+++ b/sys/contrib/ngatm/netnatm/saal/sscopdef.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 1996-2003
+ * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Hartmut Brandt <harti@freebsd.org>
+ *
+ * $Begemot: libunimsg/atm/saal/sscopdef.h,v 1.3 2003/09/19 12:02:03 hbb Exp $
+ *
+ * Definitions of SSCOP constants and parameter blocks. This is seen by
+ * the outside world.
+ */
+#ifndef _NETNATM_SAAL_SSCOPDEF_H_
+#define _NETNATM_SAAL_SSCOPDEF_H_
+
+#include <sys/types.h>
+
+/*
+ * AA-interface signals
+ */
+enum sscop_aasig {
+ SSCOP_ESTABLISH_request, /* <- UU, BR */
+ SSCOP_ESTABLISH_indication, /* -> UU */
+ SSCOP_ESTABLISH_response, /* <- UU, BR */
+ SSCOP_ESTABLISH_confirm, /* -> UU */
+
+ SSCOP_RELEASE_request, /* <- UU */
+ SSCOP_RELEASE_indication, /* -> UU, SRC */
+ SSCOP_RELEASE_confirm, /* -> */
+
+ SSCOP_DATA_request, /* <- MU */
+ SSCOP_DATA_indication, /* -> MU, SN */
+
+ SSCOP_UDATA_request, /* <- MU */
+ SSCOP_UDATA_indication, /* -> MU */
+
+ SSCOP_RECOVER_indication, /* -> */
+ SSCOP_RECOVER_response, /* <- */
+
+ SSCOP_RESYNC_request, /* <- UU */
+ SSCOP_RESYNC_indication, /* -> UU */
+ SSCOP_RESYNC_response, /* <- */
+ SSCOP_RESYNC_confirm, /* -> */
+
+ SSCOP_RETRIEVE_request, /* <- RN */
+ SSCOP_RETRIEVE_indication, /* -> MU */
+ SSCOP_RETRIEVE_COMPL_indication,/* -> */
+};
+
+enum sscop_maasig {
+ SSCOP_MDATA_request, /* <- MU */
+ SSCOP_MDATA_indication, /* -> MU */
+ SSCOP_MERROR_indication, /* -> CODE, CNT */
+};
+
+/*
+ * Values for retrieval. Numbers in SSCOP are 24bit, so
+ * we can use the large values
+ */
+enum {
+ SSCOP_MAXSEQNO = 0xffffff,
+
+ SSCOP_RETRIEVE_UNKNOWN = SSCOP_MAXSEQNO + 1,
+ SSCOP_RETRIEVE_TOTAL = SSCOP_MAXSEQNO + 2,
+};
+
+/*
+ * SSCOP states
+ */
+enum sscop_state {
+ SSCOP_IDLE, /* initial state */
+ SSCOP_OUT_PEND, /* outgoing connection pending */
+ SSCOP_IN_PEND, /* incoming connection pending */
+ SSCOP_OUT_DIS_PEND, /* outgoing disconnect pending */
+ SSCOP_OUT_RESYNC_PEND, /* outgoing resynchronisation pending */
+ SSCOP_IN_RESYNC_PEND, /* incoming resynchronisation pending */
+ SSCOP_OUT_REC_PEND, /* outgoing recovery pending */
+ SSCOP_REC_PEND, /* recovery response pending */
+ SSCOP_IN_REC_PEND, /* incoming recovery pending */
+ SSCOP_READY, /* data transfer ready */
+};
+#define SSCOP_NSTATES 10
+
+struct sscop_param {
+ uint32_t timer_cc; /* timer_cc in msec */
+ uint32_t timer_poll; /* timer_poll im msec */
+ uint32_t timer_keep_alive;/* timer_keep_alive in msec */
+ uint32_t timer_no_response;/*timer_no_response in msec */
+ uint32_t timer_idle; /* timer_idle in msec */
+ uint32_t maxk; /* maximum user data in bytes */
+ uint32_t maxj; /* maximum u-u info in bytes */
+ uint32_t maxcc; /* max. retransmissions for control packets */
+ uint32_t maxpd; /* max. vt(pd) before sending poll */
+ uint32_t maxstat; /* max. number of elements in stat list */
+ uint32_t mr; /* initial window */
+ uint32_t flags; /* flags */
+};
+enum {
+ SSCOP_ROBUST = 0x0001, /* atmf/97-0216 robustness */
+ SSCOP_POLLREX = 0x0002, /* send POLL after retransmit */
+};
+
+enum {
+ SSCOP_SET_TCC = 0x0001,
+ SSCOP_SET_TPOLL = 0x0002,
+ SSCOP_SET_TKA = 0x0004,
+ SSCOP_SET_TNR = 0x0008,
+ SSCOP_SET_TIDLE = 0x0010,
+ SSCOP_SET_MAXK = 0x0020,
+ SSCOP_SET_MAXJ = 0x0040,
+ SSCOP_SET_MAXCC = 0x0080,
+ SSCOP_SET_MAXPD = 0x0100,
+ SSCOP_SET_MAXSTAT = 0x0200,
+ SSCOP_SET_MR = 0x0400,
+ SSCOP_SET_ROBUST = 0x0800,
+ SSCOP_SET_POLLREX = 0x1000,
+
+ SSCOP_SET_ALLMASK = 0x1fff,
+};
+
+enum {
+ SSCOP_DBG_USIG = 0x0001,
+ SSCOP_DBG_TIMER = 0x0002,
+ SSCOP_DBG_BUG = 0x0004,
+ SSCOP_DBG_INSIG = 0x0008,
+ SSCOP_DBG_STATE = 0x0010,
+ SSCOP_DBG_PDU = 0x0020,
+ SSCOP_DBG_ERR = 0x0040,
+ SSCOP_DBG_EXEC = 0x0080,
+ SSCOP_DBG_FLOW = 0x0100,
+};
+
+#endif
diff --git a/sys/contrib/ngatm/netnatm/saal/sscoppriv.h b/sys/contrib/ngatm/netnatm/saal/sscoppriv.h
new file mode 100644
index 0000000..950cd59
--- /dev/null
+++ b/sys/contrib/ngatm/netnatm/saal/sscoppriv.h
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 1996-2003
+ * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Hartmut Brandt <harti@freebsd.org>
+ *
+ * $Begemot: libunimsg/atm/saal/sscoppriv.h,v 1.3 2003/09/19 12:02:03 hbb Exp $
+ *
+ * Private SSCOP definitions.
+ *
+ */
+#ifdef _KERNEL
+#ifdef __FreeBSD__
+#include <netgraph/atm/sscop/ng_sscop_cust.h>
+#endif
+#else /* !_KERNEL */
+#include "sscopcust.h"
+#endif
+
+/*
+ * PDU trailer
+ */
+union pdu {
+ u_int sscop_null;
+ struct {
+#if _BYTE_ORDER == _BIG_ENDIAN
+ u_int pl : 2; /* pad length */
+ u_int : 1; /* reserved field */
+ u_int s : 1; /* source */
+ u_int type : 4; /* PDU type */
+ u_int ns : 24; /* sequence number */
+#else
+ u_int ns : 24; /* sequence number */
+ u_int type : 4; /* PDU type */
+ u_int s : 1; /* source */
+ u_int : 1; /* reserved field */
+ u_int pl : 2; /* pad length */
+#endif
+ } ss;
+};
+#define sscop_pl ss.pl
+#define sscop_s ss.s
+#define sscop_type ss.type
+#define sscop_ns ss.ns
+
+/*
+ * seqno list entry format
+ */
+union seqno {
+ u_int sscop_null;
+ struct {
+#if _BYTE_ORDER == _BIG_ENDIAN
+ u_int : 8; /* pad */
+ u_int n : 24; /* seqno */
+#else
+ u_int n : 24; /* seqno */
+ u_int : 8; /* pad */
+#endif
+ } ss;
+};
+#define sscop_n ss.n
+
+/*
+ * Begin pdu
+ */
+union bgn {
+ u_int sscop_null;
+ struct {
+#if _BYTE_ORDER == _BIG_ENDIAN
+ u_int : 24; /* reserved */
+ u_int bgns : 8; /* VT_MR */
+#else
+ u_int bgns : 8; /* VT_MR */
+ u_int : 24; /* reserved */
+#endif
+ } ss;
+};
+#define sscop_bgns ss.bgns
+
+/*
+ * pdu types
+ */
+enum pdu_type {
+ PDU_BGN = 0x1, /* request initialization */
+ PDU_BGAK = 0x2, /* request acknowledgement */
+ PDU_END = 0x3, /* disconnect command */
+ PDU_ENDAK = 0x4, /* disconnect acknowledgement */
+ PDU_RS = 0x5, /* resynchronisation command */
+ PDU_RSAK = 0x6, /* resynchronisation acknowledgement */
+ PDU_BGREJ = 0x7, /* connection reject */
+ PDU_SD = 0x8, /* sequenced connection-mode data */
+ PDU_ER = 0x9, /* recovery command */
+ PDU_POLL = 0xa, /* xmit state info with req. for recv state */
+ PDU_STAT = 0xb, /* solicited receiver state info */
+ PDU_USTAT = 0xc, /* unsolicited receiver state info */
+ PDU_UD = 0xd, /* unumbered user data */
+ PDU_MD = 0xe, /* unumbered management data */
+ PDU_ERAK = 0xf, /* recovery acknowledgement */
+};
+
+
+/*
+ * These are all signals, that are used by SSCOP. Don't change the order or
+ * number without also changing the associated tables.
+ */
+enum sscop_sigtype {
+ /* received PDU's */
+ SIG_BGN, /* request initialization */
+ SIG_BGAK, /* request acknowledgement */
+ SIG_END, /* disconnect command */
+ SIG_ENDAK, /* disconnect acknowledgement */
+ SIG_RS, /* resynchronisation command */
+ SIG_RSAK, /* resynchronisation acknowledgement */
+ SIG_BGREJ, /* connection reject */
+ SIG_SD, /* sequenced connection-mode data */
+ SIG_ER, /* recovery command */
+ SIG_POLL, /* xmitter state info with req for recv state */
+ SIG_STAT, /* solicited receiver state info */
+ SIG_USTAT, /* unsolicited receiver state info */
+ SIG_UD, /* unumbered user data */
+ SIG_MD, /* unumbered management data */
+ SIG_ERAK, /* recovery acknoledgement */
+
+ /* timer expiry */
+ SIG_T_CC, /* CC timer */
+ SIG_T_POLL, /* POLL timer */
+ SIG_T_KA, /* KEEP ALIVE timer */
+ SIG_T_NR, /* NO RESPONSE timer */
+ SIG_T_IDLE, /* IDLE timer */
+
+ /* user originated signals */
+ SIG_PDU_Q, /* PDU enqueued pseudosignal */
+ SIG_USER_DATA, /* user data request */
+ SIG_ESTAB_REQ, /* establish connection request */
+ SIG_ESTAB_RESP, /* establish connection response */
+ SIG_RELEASE_REQ, /* release connection request */
+ SIG_RECOVER, /* automatic recover response */
+ SIG_SYNC_REQ, /* resynchronisation request */
+ SIG_SYNC_RESP, /* resynchronisation response */
+ SIG_UDATA, /* UDATA request */
+ SIG_MDATA, /* MDATA request */
+ SIG_UPDU_Q, /* UDATA PDU enqueued pseudosignal */
+ SIG_MPDU_Q, /* MDATA PDU enqueued pseudosignal */
+ SIG_RETRIEVE, /* RETRIEVE */
+
+ /* number of signals */
+ SIG_NUM
+};
+
+/*
+ * This is a message as contained in a sscop message queue. It holds a pointer
+ * to the real message.
+ */
+struct sscop_msg {
+ sscop_msgq_link_t link;
+ u_int seqno; /* seq no */
+ u_int poll_seqno; /* poll seqno (for messages in xmit buffer) */
+ u_int rexmit; /* in retransmission queue? */
+ struct SSCOP_MBUF_T *m; /* the message */
+};
+
+/*
+ * This structure is used to hold signals in the signal queue
+ */
+struct sscop_sig {
+ sscop_sigq_link_t link; /* next signal */
+ enum sscop_sigtype sig; /* THE signal */
+ struct sscop_msg *msg; /* signal argument (message) */
+};
+
+/*
+ * This structure holds the entire sscop state
+ */
+struct sscop {
+ enum sscop_state state; /* current state */
+ const struct sscop_funcs *funcs;
+
+ /* send state */
+ u_int vt_s; /* seqno for next pdu first time transmitted */
+ u_int vt_ps; /* current poll seqno */
+ u_int vt_a; /* next expected in-sequence sd pdu */
+ u_int vt_pa; /* poll seqno of next stat pdu */
+ u_int vt_ms; /* maximum allowed send sd seqno */
+ u_int vt_pd; /* poll data state */
+ u_int vt_cc; /* connection control state */
+ u_int vt_sq; /* transmitter connection sequence */
+
+ /* receive state */
+ u_int vr_r; /* receive state */
+ u_int vr_h; /* highes expected state */
+ u_int vr_mr; /* maximum acceptable */
+ u_int vr_sq; /* receiver connection state */
+
+ /* timers */
+ sscop_timer_t t_cc; /* timer_CC */
+ sscop_timer_t t_nr; /* timer_NO_RESPONSE */
+ sscop_timer_t t_ka; /* timer KEEP_ALIVE */
+ sscop_timer_t t_poll; /* timer_POLL */
+ sscop_timer_t t_idle; /* idle timer */
+
+ /* maximum values */
+ u_int maxj; /* maximum uu-info */
+ u_int maxk; /* maximum info */
+ u_int maxcc; /* maximum number of bgn, end, er and rs */
+ u_int maxpd; /* maximum value of vt_pd */
+ u_int maxstat; /* maximum length of list */
+ u_int timercc; /* connection control timer */
+ u_int timerka; /* keep alive timer */
+ u_int timernr; /* no response timer */
+ u_int timerpoll; /* polling */
+ u_int timeridle; /* idle timer */
+ u_int robustness; /* atmf/97-0216 robustness enhancement */
+ u_int poll_after_rex; /* optional POLL after re-transmission */
+ u_int mr; /* initial window */
+
+ /*
+ * buffers and queues.
+ * All expect the xq hold SD PDUs.
+ */
+ sscop_msgq_head_t xq; /* xmit queue (input from user before xmit) */
+ sscop_msgq_head_t uxq; /* UD xmit queue */
+ sscop_msgq_head_t mxq; /* MD xmit queue */
+ sscop_msgq_head_t xbuf; /* transmission buffer (SD PDUs transmitted) */
+ int rxq; /* number of PDUs in retransmission queue */
+ sscop_msgq_head_t rbuf; /* receive buffer (SD PDUs) */
+ int last_end_src; /* source field from last xmitted end pdu */
+ int clear_buffers; /* flag */
+ int credit; /* send window not closed */
+ u_int ll_busy; /* lower layer busy */
+ u_int rs_mr; /* N(MR) in last RS PDU */
+ u_int rs_sq; /* N(SQ) in last RS PDU */
+ struct SSCOP_MBUF_T *uu_bgn; /* last UU data */
+ struct SSCOP_MBUF_T *uu_bgak; /* ... */
+ struct SSCOP_MBUF_T *uu_bgrej; /* ... */
+ struct SSCOP_MBUF_T *uu_end; /* ... */
+ struct SSCOP_MBUF_T *uu_rs; /* ... */
+
+ /* signal queues */
+ sscop_sigq_head_t sigs; /* saved signals */
+ sscop_sigq_head_t saved_sigs; /* saved signals */
+ int in_sig; /* in signal handler */
+
+ /* debugging */
+ u_int debug;
+
+ /* AA interface */
+ void *aarg;
+};
+
+
+/*
+ * Default values for SSCOP
+ */
+enum {
+ MAXK = 4096,
+ MAXMAXK = 65528,
+ MAXJ = 4096,
+ MAXMAXJ = 65524,
+ MAXCC = 4,
+ MAXSTAT = 67,
+ MAXPD = 25,
+ MAXMR = 128, /* ??? */
+ TIMERCC = 1000,
+ TIMERKA = 2000,
+ TIMERNR = 7000,
+ TIMERPOLL = 750,
+ TIMERIDLE = 15000,
+};
+
+/*
+ * Sequence number arithmetic
+ */
+#define SEQNO_DIFF(A,B) (((A) < (B)) ? ((A) + (1<<24) - (B)) : ((A) - (B)))
+
+/*
+ * Debugging
+ */
+#ifdef SSCOP_DEBUG
+#define VERBOSE(S,M,F) if ((S)->debug & (M)) (S)->funcs->verbose F
+#define VERBERR(S,M,F) if ((S)->debug & (M)) (S)->funcs->verbose F
+#define ISVERBOSE(S,M) ((S)->debug & (M))
+#else
+#define VERBOSE(S,M,F)
+#define VERBERR(S,M,F)
+#define ISVERBOSE(S,M) (0)
+#endif
diff --git a/sys/contrib/ngatm/netnatm/unimsg.h b/sys/contrib/ngatm/netnatm/unimsg.h
new file mode 100644
index 0000000..d5b390c
--- /dev/null
+++ b/sys/contrib/ngatm/netnatm/unimsg.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1996-2003
+ * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Hartmut Brandt <harti@freebsd.org>
+ *
+ * $Begemot: libunimsg/atm/unimsg.h,v 1.3 2003/09/19 11:52:40 hbb Exp $
+ *
+ * This defines the structure of messages as handled by this library.
+ */
+#ifndef _NETNATM_UNIMSG_H_
+#define _NETNATM_UNIMSG_H_
+
+#include <sys/types.h>
+#ifdef _KERNEL
+#ifdef __FreeBSD__
+#include <sys/systm.h>
+#endif
+#else
+#include <string.h>
+#endif
+
+struct uni_msg {
+ u_char *b_wptr; /* tail pointer */
+ u_char *b_rptr; /* head pointer */
+ u_char *b_buf; /* data buffer */
+ u_char *b_lim; /* end of data buffer */
+};
+
+/* return the current length of the message */
+#define uni_msg_len(M) ((size_t)((M)->b_wptr - (M)->b_rptr))
+
+/* return the number of space behind the message */
+#define uni_msg_space(M) ((size_t)((M)->b_lim - (M)->b_wptr))
+
+/* return the amount of leading free space */
+#define uni_msg_leading(M) ((size_t)((M)->b_rptr - (M)->b_buf))
+
+/* return the maximum size of the message (length plus free space) */
+#define uni_msg_size(M) ((size_t)((M)->b_lim - (M)->b_buf));
+
+/* ensure that there is space for another S bytes. If reallocation fails
+ * free message and return -1 */
+#define uni_msg_ensure(M, S) \
+ ((uni_msg_space(M) >= (S)) ? 0 : uni_msg_extend(M, S))
+
+int uni_msg_append(struct uni_msg *, void *, size_t);
+int uni_msg_extend(struct uni_msg *, size_t);
+
+#define uni_msg_rptr(MSG, TYPE) ((TYPE)(void *)(MSG)->b_rptr)
+#define uni_msg_wptr(MSG, TYPE) ((TYPE)(void *)(MSG)->b_wptr)
+
+int uni_msg_prepend(struct uni_msg *, size_t);
+
+#ifndef _KERNEL
+
+struct uni_msg *uni_msg_alloc(size_t);
+struct uni_msg *uni_msg_build(void *, ...);
+void uni_msg_destroy(struct uni_msg *);
+u_int uni_msg_strip32(struct uni_msg *);
+u_int uni_msg_get32(struct uni_msg *);
+int uni_msg_append32(struct uni_msg *, u_int);
+int uni_msg_append8(struct uni_msg *, u_int);
+u_int uni_msg_trail32(const struct uni_msg *, int);
+struct uni_msg *uni_msg_dup(const struct uni_msg *);
+
+#endif /* _KERNEL */
+#endif
OpenPOWER on IntegriCloud