summaryrefslogtreecommitdiffstats
path: root/sys/contrib/ngatm
diff options
context:
space:
mode:
authorharti <harti@FreeBSD.org>2003-11-07 08:46:22 +0000
committerharti <harti@FreeBSD.org>2003-11-07 08:46:22 +0000
commita92d6f1ef6b5ff4215d1d644cbf12ab1fcb8f8c0 (patch)
treee4cb95f047c8ee14d254892524f10bddcd806c07 /sys/contrib/ngatm
parentd2e4a0c64439be23c448c5da91bb2bbfa709d38c (diff)
downloadFreeBSD-src-a92d6f1ef6b5ff4215d1d644cbf12ab1fcb8f8c0.zip
FreeBSD-src-a92d6f1ef6b5ff4215d1d644cbf12ab1fcb8f8c0.tar.gz
Virgin import of signaling layer of NgATM shared kernel/user part 0.91
Diffstat (limited to 'sys/contrib/ngatm')
-rw-r--r--sys/contrib/ngatm/netnatm/sig/genmsgcpyc.awk80
-rw-r--r--sys/contrib/ngatm/netnatm/sig/genmsgcpyh.awk55
-rw-r--r--sys/contrib/ngatm/netnatm/sig/sig_call.c4300
-rw-r--r--sys/contrib/ngatm/netnatm/sig/sig_coord.c1171
-rw-r--r--sys/contrib/ngatm/netnatm/sig/sig_party.c1353
-rw-r--r--sys/contrib/ngatm/netnatm/sig/sig_print.c622
-rw-r--r--sys/contrib/ngatm/netnatm/sig/sig_reset.c824
-rw-r--r--sys/contrib/ngatm/netnatm/sig/sig_uni.c749
-rw-r--r--sys/contrib/ngatm/netnatm/sig/sig_verify.c442
-rw-r--r--sys/contrib/ngatm/netnatm/sig/uni.h106
-rw-r--r--sys/contrib/ngatm/netnatm/sig/unidef.h474
-rw-r--r--sys/contrib/ngatm/netnatm/sig/unimkmsg.h159
-rw-r--r--sys/contrib/ngatm/netnatm/sig/unipriv.h544
-rw-r--r--sys/contrib/ngatm/netnatm/sig/unisig.h49
14 files changed, 10928 insertions, 0 deletions
diff --git a/sys/contrib/ngatm/netnatm/sig/genmsgcpyc.awk b/sys/contrib/ngatm/netnatm/sig/genmsgcpyc.awk
new file mode 100644
index 0000000..ca347ac
--- /dev/null
+++ b/sys/contrib/ngatm/netnatm/sig/genmsgcpyc.awk
@@ -0,0 +1,80 @@
+#
+# Copyright (c) 2001-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/sig/genmsgcpyc.awk,v 1.3 2003/09/19 12:03:33 hbb Exp $
+#
+# Generate copy functions for messages
+#
+function begin() {
+}
+
+function first_entry() {
+ print "/* This file was created automatically"
+ print " * Source file: " id
+ print " * $FreeBSD$"
+ print " */"
+ print ""
+ print "#include <netnatm/msg/unistruct.h>"
+ print "#include <netnatm/sig/unimsgcpy.h>"
+}
+
+function end() {
+}
+
+function start_message() {
+}
+
+function end_message() {
+ print ""
+ print "void"
+ print "copy_msg_" msg "(struct uni_" msg " *src, struct uni_" msg " *dst)"
+ print "{"
+ for(i = 0; i < cnt; i++) {
+ if(ienum[i] != "-") {
+ print "\tu_int s, d;"
+ print ""
+ break
+ }
+ }
+ for(i = 0; i < cnt; i++) {
+ ie = iename[i]
+ if(ierep[i]) {
+ print "\tif(IE_ISGOOD(src->" ie "_repeat))"
+ print "\t\tdst->" ie "_repeat = src->" ie "_repeat;"
+ }
+ if(ienum[i] != "-") {
+ print "\tfor(s = d = 0; s < "ienum[i]"; s++)"
+ print "\t\tif(IE_ISGOOD(src->"ie"[s]))"
+ print "\t\t\tdst->"ie"[d++] = src->"ie"[s];"
+ } else {
+ print "\tif(IE_ISGOOD(src->"ie"))"
+ print "\t\tdst->"ie" = src->"ie";"
+ }
+ }
+ print "}"
+}
diff --git a/sys/contrib/ngatm/netnatm/sig/genmsgcpyh.awk b/sys/contrib/ngatm/netnatm/sig/genmsgcpyh.awk
new file mode 100644
index 0000000..0b50688
--- /dev/null
+++ b/sys/contrib/ngatm/netnatm/sig/genmsgcpyh.awk
@@ -0,0 +1,55 @@
+#
+# Copyright (c) 2001-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/sig/genmsgcpyh.awk,v 1.3 2003/09/19 12:03:33 hbb Exp $
+#
+# Generate copy functions for messages
+#
+function begin() {
+}
+
+function first_entry() {
+ print "/* This file was created automatically"
+ print " * Source file: " id
+ print " * $FreeBSD$"
+ print " */"
+ print ""
+}
+
+function end() {
+}
+
+function start_message() {
+}
+
+function end_message() {
+ print ""
+ print "void"
+ print "copy_msg_" msg "(struct uni_" msg " *src, struct uni_" msg " *dst);"
+ print ""
+}
diff --git a/sys/contrib/ngatm/netnatm/sig/sig_call.c b/sys/contrib/ngatm/netnatm/sig/sig_call.c
new file mode 100644
index 0000000..e11c52f
--- /dev/null
+++ b/sys/contrib/ngatm/netnatm/sig/sig_call.c
@@ -0,0 +1,4300 @@
+/*
+ * 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/sig/sig_call.c,v 1.61 2003/10/16 13:35:44 hbb Exp $
+ *
+ * Call instance handling
+ *
+ * Note:
+ * In all functions that handle messages from the user or from
+ * the SAAL, commit memory allocation always at the begin of the
+ * function. If allocation fails, ignore saal messages and
+ * respond with an error to user messages.
+ */
+
+#include <netnatm/unimsg.h>
+#include <netnatm/saal/sscfudef.h>
+#include <netnatm/msg/unistruct.h>
+#include <netnatm/msg/unimsglib.h>
+#include <netnatm/sig/uni.h>
+
+#include <netnatm/sig/unipriv.h>
+#include <netnatm/sig/unimkmsg.h>
+#include <netnatm/sig/unimsgcpy.h>
+
+static enum call_state state_compat(struct call *, enum uni_callstate);
+static void respond_drop_party_ack(struct call *, struct uni_ie_epref *, u_int);
+
+
+#define DEF_PRIV_SIG(NAME, FROM) [SIG##NAME] "SIG"#NAME,
+static const char *const call_sigs[] = {
+ DEF_CALL_SIGS
+};
+#undef DEF_PRIV_SIG
+
+TIMER_FUNC_CALL(t308, t308_func)
+TIMER_FUNC_CALL(t303, t303_func)
+TIMER_FUNC_CALL(t301, t301_func)
+TIMER_FUNC_CALL(t310, t310_func)
+TIMER_FUNC_CALL(t313, t313_func)
+TIMER_FUNC_CALL(t322, t322_func)
+
+const struct callstates callstates[] = {
+ [CALLST_NULL] { "NU0", UNI_CALLSTATE_U0 },
+ [CALLST_U1] { "U1", UNI_CALLSTATE_U1 },
+ [CALLST_U3] { "U3", UNI_CALLSTATE_U3 },
+ [CALLST_U4] { "U4", UNI_CALLSTATE_U4 },
+ [CALLST_U6] { "U6", UNI_CALLSTATE_U6 },
+ [CALLST_U7] { "U7", UNI_CALLSTATE_U7 },
+ [CALLST_U8] { "U8", UNI_CALLSTATE_U8 },
+ [CALLST_U9] { "U9", UNI_CALLSTATE_U9 },
+ [CALLST_U10] { "U10", UNI_CALLSTATE_U10 },
+ [CALLST_U11] { "U11", UNI_CALLSTATE_U11 },
+ [CALLST_U12] { "U12", UNI_CALLSTATE_U12 },
+ [CALLST_N1] { "N1", UNI_CALLSTATE_N1 },
+ [CALLST_N3] { "N3", UNI_CALLSTATE_N3 },
+ [CALLST_N4] { "N4", UNI_CALLSTATE_N4 },
+ [CALLST_N6] { "N6", UNI_CALLSTATE_N6 },
+ [CALLST_N7] { "N7", UNI_CALLSTATE_N7 },
+ [CALLST_N8] { "N8", UNI_CALLSTATE_N8 },
+ [CALLST_N9] { "N9", UNI_CALLSTATE_N9 },
+ [CALLST_N10] { "N10", UNI_CALLSTATE_N10 },
+ [CALLST_N11] { "N11", UNI_CALLSTATE_N11 },
+ [CALLST_N12] { "N12", UNI_CALLSTATE_N12 },
+};
+
+static void unx_send_add_party_rej(struct call *c, struct uni_all *u);
+
+static __inline void
+set_call_state(struct call *c, enum call_state state)
+{
+ ASSERT(state == CALLST_NULL ||
+ (c->uni->proto == UNIPROTO_UNI40U &&
+ (state >= CALLST_U1 && state <= CALLST_U12)) ||
+ (c->uni->proto == UNIPROTO_UNI40N &&
+ (state >= CALLST_N1 && state <= CALLST_N12)),
+ ("setting wrong callstate for proto %u: %u", c->uni->proto, state));
+
+ if (c->cstate != state) {
+ VERBOSE(c->uni, UNI_FAC_CALL, 1, "call %d/%d %s -> %s",
+ c->cref, c->mine, callstates[c->cstate].name,
+ callstates[state].name);
+ c->cstate = state;
+ }
+}
+
+static enum uni_callstate
+map_callstate(enum call_state state)
+{
+ return (callstates[state].ext);
+}
+
+/*
+ * Find the call. Assume, that the cref is one of a message just received.
+ * That is, if the call reference flag is 0 it is his call, if it is 1 it
+ * is my call.
+ */
+struct call *
+uni_find_call(struct uni *uni, struct uni_cref *cref)
+{
+ struct call *c;
+
+ TAILQ_FOREACH(c, &uni->calls, link)
+ if (c->cref == cref->cref && (!c->mine == !cref->flag))
+ return (c);
+ return (NULL);
+}
+struct call *
+uni_find_callx(struct uni *uni, u_int cref, u_int mine)
+{
+ struct call *c;
+
+ TAILQ_FOREACH(c, &uni->calls, link)
+ if (c->cref == cref && !c->mine == !mine)
+ return (c);
+ return (NULL);
+}
+
+/*
+ * Create a new call instance. The type must be set by the caller.
+ */
+struct call *
+uni_create_call(struct uni *uni, u_int cref, u_int mine, u_int32_t cookie)
+{
+ struct call *c;
+ struct uniapi_call_created *ind;
+ struct uni_msg *api;
+
+ if ((c = CALL_ALLOC()) == NULL)
+ return (NULL);
+
+ if ((ind = ALLOC_API(struct uniapi_call_created, api)) == NULL) {
+ CALL_FREE(c);
+ return (NULL);
+ }
+ ind->cref.cref = cref;
+ ind->cref.flag = mine;
+
+ c->uni = uni;
+ c->type = CALL_NULL;
+ c->cref = cref;
+ c->mine = mine;
+ c->cstate = CALLST_NULL;
+ TAILQ_INIT(&c->parties);
+
+ TIMER_INIT_CALL(c, t301);
+ TIMER_INIT_CALL(c, t303);
+ TIMER_INIT_CALL(c, t308);
+ TIMER_INIT_CALL(c, t310);
+ TIMER_INIT_CALL(c, t313);
+ TIMER_INIT_CALL(c, t322);
+
+ TAILQ_INSERT_HEAD(&uni->calls, c, link);
+
+ uni->funcs->uni_output(uni, uni->arg, UNIAPI_CALL_CREATED, cookie, api);
+
+ VERBOSE(c->uni, UNI_FAC_CALL, 1, "created call %u/%s",
+ c->cref, c->mine ? "mine" : "his");
+
+ return (c);
+}
+
+struct call *
+uni_create_new_call(struct uni *uni, u_int32_t cookie)
+{
+ struct call *c;
+ u_int32_t old = uni->cref_alloc++;
+
+ again:
+ if (uni->cref_alloc == (1 << 23))
+ uni->cref_alloc = 1;
+ if (uni->cref_alloc == old)
+ return (NULL); /* all crefs exhausted!!! */
+ TAILQ_FOREACH(c, &uni->calls, link)
+ if (c->mine && c->cref == uni->cref_alloc) {
+ uni->cref_alloc++;
+ goto again;
+ }
+ return (uni_create_call(uni, uni->cref_alloc, 1, cookie));
+}
+
+/*
+ * Assume timers are all stopped. Memory is not actually freed unless
+ * the reference count drops to 0.
+ * This function is assumed to remove the call from the parent UNI's
+ * call queue.
+ */
+void
+uni_destroy_call(struct call *c, int really)
+{
+ struct uniapi_call_destroyed *ind;
+ struct uni_msg *api;
+ struct party *p;
+
+ VERBOSE(c->uni, UNI_FAC_CALL, 1, "destroying call %u/%s",
+ c->cref, c->mine ? "mine" : "his");
+
+ TIMER_DESTROY_CALL(c, t301);
+ TIMER_DESTROY_CALL(c, t303);
+ TIMER_DESTROY_CALL(c, t308);
+ TIMER_DESTROY_CALL(c, t310);
+ TIMER_DESTROY_CALL(c, t313);
+ TIMER_DESTROY_CALL(c, t322);
+ TAILQ_REMOVE(&c->uni->calls, c, link);
+
+ uni_delsig(c->uni, SIG_CALL, c, NULL);
+
+ while ((p = TAILQ_FIRST(&c->parties)) != NULL) {
+ TAILQ_REMOVE(&c->parties, p, link);
+ uni_destroy_party(p, really);
+ }
+
+ if (!really) {
+ ind = ALLOC_API(struct uniapi_call_destroyed, api);
+ if (ind != NULL) {
+ ind->cref.cref = c->cref;
+ ind->cref.flag = c->mine;
+
+ uni_enq_coord(c->uni, SIGO_CALL_DESTROYED, 0, api);
+ }
+
+ uni_enq_call(c, SIGC_CALL_DELETE, 0, NULL, NULL);
+ return;
+ }
+
+ CALL_FREE(c);
+}
+
+static void
+allocate_epref(struct call *c, struct uni_ie_epref *epref)
+{
+ struct party *p;
+ u_int32_t old = c->epref_alloc++;
+
+ again:
+ if (c->epref_alloc == (1 << 15))
+ c->epref_alloc = 0;
+ if (c->epref_alloc == old)
+ return; /* all crefs exhausted!!! */
+ TAILQ_FOREACH(p, &c->parties, link)
+ if (p->epref == c->epref_alloc) {
+ c->epref_alloc++;
+ goto again;
+ }
+ IE_SETPRESENT(*epref);
+ epref->flag = 0;
+ epref->epref = c->epref_alloc;
+
+ epref->h.coding = UNI_CODING_ITU;
+ epref->h.act = UNI_IEACT_DEFAULT;
+}
+
+static void
+reset_all_timers(struct call *c)
+{
+ TIMER_STOP_CALL(c, t301);
+ TIMER_STOP_CALL(c, t303);
+ TIMER_STOP_CALL(c, t308);
+ TIMER_STOP_CALL(c, t310);
+ TIMER_STOP_CALL(c, t313);
+ TIMER_STOP_CALL(c, t322);
+}
+
+/*
+ * Initiate call clearing because of a problem. This is label D in
+ * the SDLs and is called from many places.
+ * The call must have constructed the cause IE in struct call.
+ *
+ * Q.2971:Call-Control-U 27/39
+ * Q.2971:Call-Control-N 28/39
+ *
+ * Memory problems are handled differently here: we simply ignore them
+ * by not sending messages or user indications. Because of T308 we
+ * may be lucky to send the message in a second run.
+ *
+ * It is assumed, that the cause for the release is constructed by
+ * the calling function in uni->cause.
+ */
+static void
+clear_callD(struct call *c)
+{
+ struct uni_msg *api;
+ struct uniapi_release_indication *ind;
+ struct party *p;
+ struct uni_all *rel;
+
+ /*
+ * Send indication to API
+ */
+ if ((ind = ALLOC_API(struct uniapi_release_indication, api)) != NULL) {
+ ind->release.hdr.cref.cref = c->cref;
+ ind->release.hdr.cref.flag = c->mine;
+ ind->release.hdr.act = UNI_MSGACT_DEFAULT;
+ ind->release.cause[0] = c->uni->cause;
+
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_RELEASE_indication, 0, api);
+ }
+
+ reset_all_timers(c);
+
+ if (c->type == CALL_LEAF || c->type == CALL_ROOT) {
+ TAILQ_FOREACH(p, &c->parties, link) {
+ uni_enq_party(p, SIGP_RELEASE_request, 0, NULL, NULL);
+ }
+ }
+
+ memset(&c->msg_release, 0, sizeof(c->msg_release));
+ c->msg_release.cause[0] = c->uni->cause;
+
+ if ((rel = UNI_ALLOC()) != NULL) {
+ rel->u.release = c->msg_release;
+ MK_MSG_ORIG(rel, UNI_RELEASE, c->cref, !c->mine);
+ (void)uni_send_output(rel, c->uni);
+ UNI_FREE(rel);
+ }
+
+ TIMER_START_CALL(c, t308, c->uni->timer308);
+ c->cnt308 = 0;
+
+ if (c->uni->proto == UNIPROTO_UNI40N)
+ set_call_state(c, CALLST_N12);
+ else
+ set_call_state(c, CALLST_U11);
+}
+
+
+/**********************************************************************/
+/*
+ * SETUP message in state NULL
+ *
+ * Q.2971:Call-Control-U 4/39
+ * Q.2971:Call-Control-N 4/39
+ */
+static void
+un0_setup(struct call *c, struct uni_msg *m, struct uni_all *u,
+ enum call_state new_state)
+{
+ struct uni_all *resp;
+ struct party *p;
+ struct uniapi_setup_indication *ind;
+ struct uni_msg *api;
+ enum verify v;
+
+ if ((ind = ALLOC_API(struct uniapi_setup_indication, api)) == NULL) {
+ clear:
+ uni_destroy_call(c, 0);
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+ return;
+ }
+
+ /*
+ * Analyze message
+ */
+ (void)uni_decode_body(m, u, &c->uni->cx);
+ MANDATE_IE(c->uni, u->u.setup.bearer, UNI_IE_BEARER);
+ MANDATE_IE(c->uni, u->u.setup.traffic, UNI_IE_TRAFFIC);
+ MANDATE_IE(c->uni, u->u.setup.called, UNI_IE_CALLED);
+
+ /*
+ * UNI4.0: 9.1.1.2 Notes 2/3
+ */
+ if (!IE_ISPRESENT(u->u.setup.qos))
+ MANDATE_IE(c->uni, u->u.setup.exqos, UNI_IE_EXQOS);
+ if (!IE_ISPRESENT(u->u.setup.exqos))
+ MANDATE_IE(c->uni, u->u.setup.qos, UNI_IE_QOS);
+
+ /*
+ * Q.2971
+ */
+ if (IE_ISGOOD(u->u.setup.bearer) &&
+ u->u.setup.bearer.cfg == UNI_BEARER_MP) {
+ if (IE_ISGOOD(u->u.setup.epref) &&
+ u->u.setup.epref.flag == 1) {
+ IE_SETERROR(u->u.setup.epref);
+ UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF,
+ u->u.setup.epref.h.act, UNI_IERR_BAD);
+ }
+ uni_mandate_epref(c->uni, &u->u.setup.epref);
+ }
+
+ v = uni_verify(c->uni, u->u.hdr.act);
+ switch (v) {
+
+ case VFY_RAI:
+ uni_respond_status_verify(c->uni, &u->u.hdr.cref,
+ UNI_CALLSTATE_U0, NULL, 0);
+ /* FALLTHRU */
+ case VFY_I:
+ uni_msg_destroy(api);
+ goto clear;
+
+ case VFY_RAIM:
+ case VFY_CLR:
+ if ((resp = UNI_ALLOC()) != NULL) {
+ MK_MSG_RESP(resp, UNI_RELEASE_COMPL, &u->u.hdr.cref);
+ uni_vfy_collect_ies(c->uni);
+ resp->u.release_compl.cause[0] = c->uni->cause;
+ uni_send_output(resp, c->uni);
+ UNI_FREE(resp);
+ }
+ uni_msg_destroy(api);
+ goto clear;
+
+ case VFY_RAP:
+ case VFY_RAPU:
+ uni_respond_status_verify(c->uni, &u->u.hdr.cref,
+ map_callstate(new_state), NULL, 0);
+ /* FALLTHRU */
+ case VFY_OK:
+ break;
+ }
+
+ if (u->u.setup.bearer.cfg == UNI_BEARER_P2P) {
+ c->type = CALL_P2P;
+
+ } else {
+ c->type = CALL_LEAF;
+ if ((p = uni_create_party(c, &u->u.setup.epref)) == NULL) {
+ uni_msg_destroy(api);
+ goto clear;
+ }
+ uni_enq_party(p, SIGP_SETUP, 0, NULL, NULL);
+ }
+
+ ind->setup.hdr = u->u.hdr;
+ copy_msg_setup(&u->u.setup, &ind->setup);
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_SETUP_indication, 0, api);
+
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+
+ set_call_state(c, new_state);
+}
+
+/*
+ * Setup.request from user
+ *
+ * Q.2971:Call-Control-U 4/39 (U0)
+ * Q.2971:Call-Control-N 4/39 (N0)
+ */
+static void
+un0_setup_request(struct call *c, struct uni_msg *m, u_int32_t cookie,
+ enum call_state new_state)
+{
+ struct uniapi_setup_request *arg =
+ uni_msg_rptr(m, struct uniapi_setup_request *);
+ struct uni_setup *setup = &arg->setup;
+ struct uni_all *out;
+ struct party *p;
+
+ if (!IE_ISGOOD(setup->bearer)) {
+ uni_msg_destroy(m);
+ uniapi_call_error(c, UNIAPI_ERROR_MISSING_IE, cookie);
+ uni_destroy_call(c, 0);
+ return;
+ }
+ if ((out = UNI_ALLOC()) == NULL) {
+ uni_msg_destroy(m);
+ uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
+ uni_destroy_call(c, 0);
+ return;
+ }
+
+ c->msg_setup = *setup;
+
+ if (IE_ISGOOD(setup->connid))
+ c->connid = setup->connid;
+
+ if (setup->bearer.cfg == UNI_BEARER_P2P) {
+ c->type = CALL_P2P;
+ } else {
+ c->type = CALL_ROOT;
+
+ /*
+ * If the user didn't specify a endpoint reference,
+ * use 0. Use IE_IGNORE accoring to Appendix II Q.2971
+ */
+ if (!IE_ISPRESENT(c->msg_setup.epref)) {
+ MK_IE_EPREF(c->msg_setup.epref, 0, 0);
+ if (c->uni->proto == UNIPROTO_UNI40N)
+ c->msg_setup.epref.h.act = UNI_IEACT_IGNORE;
+
+ } else if (!IE_ISGOOD(c->msg_setup.epref)) {
+ uni_msg_destroy(m);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
+ uni_destroy_call(c, 0);
+ return;
+ }
+ if ((p = uni_create_partyx(c, 0, 1, cookie)) == NULL) {
+ uni_msg_destroy(m);
+ uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
+ uni_destroy_call(c, 0);
+ return;
+ }
+ uni_enq_party(p, SIGP_SETUP_request, cookie, NULL, NULL);
+ }
+
+ uni_msg_destroy(m);
+
+ out->u.setup = c->msg_setup;
+ MK_MSG_ORIG(out, UNI_SETUP, c->cref, !c->mine);
+ (void)uni_send_output(out, c->uni);
+ UNI_FREE(out);
+
+ TIMER_START_CALL(c, t303, c->uni->timer303);
+ c->cnt303 = 0;
+
+ set_call_state(c, new_state);
+
+ uniapi_call_error(c, UNIAPI_OK, cookie);
+}
+
+/*
+ * CALL PROCEEDING message
+ *
+ * Q.2971:Call-Control-U 6/39 (in U1)
+ * Q.2971:Call-Control-N 11/39 (in N6)
+ */
+static void
+u1n6_call_proc(struct call *c, struct uni_msg *m, struct uni_all *u,
+ enum call_state new_state)
+{
+ struct uni_call_proc *cp = &u->u.call_proc;
+ struct uniapi_proceeding_indication *ind;
+ struct uni_msg *api;
+
+ ind = ALLOC_API(struct uniapi_proceeding_indication, api);
+ if (ind == NULL) {
+ ignore:
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+ return;
+ }
+ /*
+ * Analyze message
+ */
+ (void)uni_decode_body(m, u, &c->uni->cx);
+ if (!IE_ISPRESENT(c->connid) && !IE_ISGOOD(cp->connid))
+ uni_mandate_ie(c->uni, UNI_IE_CONNID);
+
+ /*
+ * Q.2971: L3MU_01_03 requests us to ignore the message if
+ * the EPREF is missing.
+ */
+ if (c->msg_setup.bearer.cfg == UNI_BEARER_MP &&
+ IE_ISPRESENT(c->msg_setup.epref)) {
+ if (!IE_ISPRESENT(cp->epref))
+ uni_mandate_ie(c->uni, UNI_IE_EPREF); \
+
+ else if (IE_ISGOOD(cp->epref) &&
+ (cp->epref.flag != 1 ||
+ cp->epref.epref != c->msg_setup.epref.epref)) {
+ IE_SETERROR(cp->epref);
+ UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF,
+ cp->epref.h.act, UNI_IERR_BAD);
+ }
+ }
+
+ switch (uni_verify(c->uni, u->u.hdr.act)) {
+
+ case VFY_CLR:
+ uni_vfy_collect_ies(c->uni);
+ clear_callD(c);
+ /* FALLTHRU */
+ case VFY_I:
+ uni_msg_destroy(api);
+ goto ignore;
+
+ case VFY_RAIM:
+ case VFY_RAI:
+ report:
+ uni_respond_status_verify(c->uni, &u->u.hdr.cref,
+ map_callstate(c->cstate), NULL, 0);
+ uni_msg_destroy(api);
+ goto ignore;
+
+ case VFY_RAP:
+ case VFY_RAPU:
+ if (c->type == CALL_ROOT && !IE_ISGOOD(cp->epref))
+ goto report;
+ uni_respond_status_verify(c->uni, &u->u.hdr.cref,
+ map_callstate(new_state), NULL, 0);
+ /* FALLTHRU */
+ case VFY_OK:
+ break;
+ }
+
+ TIMER_STOP_CALL(c, t303);
+
+ if (IE_ISGOOD(cp->connid))
+ c->connid = cp->connid;
+
+ ind->call_proc.hdr = u->u.hdr;
+ copy_msg_call_proc(cp, &ind->call_proc);
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_PROCEEDING_indication, 0, api);
+
+ TIMER_START_CALL(c, t310, c->uni->timer310);
+
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+
+ set_call_state(c, new_state);
+}
+
+/*
+ * T303 tick.
+ *
+ * Q.2971:Call-Control-U 6/39
+ * Q.2971:Call-Control-N 11/39
+ */
+static void
+u1n6_t303(struct call *c)
+{
+ struct uni_all *msg;
+ struct uniapi_release_confirm *conf;
+ struct uni_msg *api;
+
+ VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T303 tick %d",
+ c->cref, c->mine ? "mine" : "his", c->cnt303 + 1);
+
+ if (++c->cnt303 < c->uni->init303) {
+ if ((msg = UNI_ALLOC()) != NULL) {
+ msg->u.setup = c->msg_setup;
+ MK_MSG_ORIG(msg, UNI_SETUP, c->cref, !c->mine);
+ (void)uni_send_output(msg, c->uni);
+ UNI_FREE(msg);
+ }
+ TIMER_START_CALL(c, t303, c->uni->timer303);
+ return;
+ }
+
+ /*
+ * Send indication to API
+ */
+ if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) != NULL) {
+ conf->release.hdr.cref.cref = c->cref;
+ conf->release.hdr.cref.flag = c->mine;
+ conf->release.hdr.act = UNI_MSGACT_DEFAULT;
+ MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_NO_RESPONSE);
+
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_RELEASE_confirm, 0, api);
+ }
+
+ /*
+ * send to party (there may be only one)
+ */
+ if (c->type == CALL_ROOT && !TAILQ_EMPTY(&c->parties)) {
+ uni_enq_party(TAILQ_FIRST(&c->parties),
+ SIGP_RELEASE_confirm, 0, NULL, NULL);
+ }
+ uni_destroy_call(c, 0);
+}
+
+/*
+ * T310 (Call Proceeding) timer tick.
+ *
+ * Q.2971:Call-Control-U 7/39
+ * Q.2971:Call-Control-N 17/39
+ */
+static void
+u3n9_t310(struct call *c)
+{
+ VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T310 tick",
+ c->cref, c->mine ? "mine" : "his");
+
+ MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_NO_RESPONSE);
+ clear_callD(c);
+}
+
+/*
+ * T301 (Alerting) timer tick.
+ *
+ * Q.2971:Call-Control-U Missing
+ * Q.2971:Call-Control-N 14/39
+ */
+static void
+u4n7_t301(struct call *c)
+{
+ VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T301 tick",
+ c->cref, c->mine ? "mine" : "his");
+
+ MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_NO_RESP_ALERT);
+ clear_callD(c);
+}
+
+/*
+ * ALERTING received
+ *
+ * Q.2971:Call-Control-U 37/39 (U1)
+ * Q.2971:Call-Control-U 7/39 (U3)
+ * Q.2971:Call-Control-N 9/39 (N6)
+ * Q.2971:Call-Control-N 17/39 (N9)
+ *
+ * There are two errors in the user side SDL Annex A:
+ *
+ * - the resetted timers are swapped (T310 and T303)
+ *
+ * - for U1 we should go to C12, not C3 to start T301.
+ */
+static void
+unx_alerting(struct call *c, struct uni_msg *m, struct uni_all *u,
+ enum call_state new_state)
+{
+ struct uni_alerting *al = &u->u.alerting;
+ struct uniapi_alerting_indication *ind;
+ struct uni_msg *api;
+
+ ind = ALLOC_API(struct uniapi_alerting_indication, api);
+ if (ind == NULL) {
+ ignore:
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+ return;
+ }
+
+ /*
+ * Analyze message
+ */
+ (void)uni_decode_body(m, u, &c->uni->cx);
+ if (!IE_ISPRESENT(c->connid) && !IE_ISGOOD(al->connid))
+ uni_mandate_ie(c->uni, UNI_IE_CONNID);
+
+ /*
+ * Q.2971: L3MU_01_04 requests us to ignore the message if the
+ * EPREF is missing.
+ */
+ if (c->msg_setup.bearer.cfg == UNI_BEARER_MP &&
+ IE_ISPRESENT(c->msg_setup.epref)) {
+ if (!IE_ISPRESENT(al->epref))
+ uni_mandate_ie(c->uni, UNI_IE_EPREF); \
+
+ else if (IE_ISGOOD(al->epref) &&
+ (al->epref.flag != 1 ||
+ al->epref.epref != c->msg_setup.epref.epref)) {
+ IE_SETERROR(al->epref);
+ UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF,
+ al->epref.h.act, UNI_IERR_BAD);
+ }
+ }
+
+ switch (uni_verify(c->uni, u->u.hdr.act)) {
+
+ case VFY_CLR:
+ uni_vfy_collect_ies(c->uni);
+ clear_callD(c);
+ case VFY_I:
+ uni_msg_destroy(api);
+ goto ignore;
+
+ case VFY_RAIM:
+ case VFY_RAI:
+ report:
+ uni_respond_status_verify(c->uni, &u->u.hdr.cref,
+ map_callstate(c->cstate), NULL, 0);
+ uni_msg_destroy(api);
+ goto ignore;
+
+ case VFY_RAP:
+ case VFY_RAPU:
+ if (c->type == CALL_ROOT && !IE_ISGOOD(al->epref))
+ goto report;
+ uni_respond_status_verify(c->uni, &u->u.hdr.cref,
+ map_callstate(c->cstate), NULL, 0);
+ case VFY_OK:
+ break;
+ }
+
+ if (c->cstate == CALLST_U1 || c->cstate == CALLST_N6)
+ TIMER_STOP_CALL(c, t303);
+ else if (c->cstate == CALLST_U3 || c->cstate == CALLST_N9)
+ TIMER_STOP_CALL(c, t310);
+
+ if (IE_ISGOOD(al->connid))
+ c->connid = al->connid;
+
+ ind->alerting.hdr = u->u.hdr;
+ copy_msg_alerting(al, &ind->alerting);
+
+ if (c->type == CALL_LEAF || c->type == CALL_ROOT) {
+ uni_enq_party(TAILQ_FIRST(&c->parties), SIGP_ALERTING,
+ 0, NULL, NULL);
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_ALERTING_indication, 0, api);
+ } else {
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_ALERTING_indication, 0, api);
+ TIMER_START_CALL(c, t301, c->uni->timer301);
+ }
+ UNI_FREE(u);
+ uni_msg_destroy(m);
+
+ set_call_state(c, new_state);
+}
+
+/*
+ * Proceeding.request from API
+ *
+ * Q.2971:Call-Control-U 12/39 (U6)
+ * Q.2971:Call-Control-N 6/39 (N1)
+ */
+static void
+u6n1_proceeding_request(struct call *c, struct uni_msg *m, u_int32_t cookie,
+ enum call_state new_state)
+{
+ struct uni_all *msg;
+ struct uniapi_proceeding_request *arg =
+ uni_msg_rptr(m, struct uniapi_proceeding_request *);
+
+ if ((msg = UNI_ALLOC()) == NULL) {
+ uni_msg_destroy(m);
+ uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
+ return;
+ }
+
+ if (IE_ISGOOD(arg->call_proc.connid))
+ c->connid = arg->call_proc.connid;
+
+ msg->u.call_proc = arg->call_proc;
+ MK_MSG_ORIG(msg, UNI_CALL_PROC, c->cref, !c->mine);
+ (void)uni_send_output(msg, c->uni);
+ UNI_FREE(msg);
+
+ set_call_state(c, new_state);
+
+ uni_msg_destroy(m);
+
+ uniapi_call_error(c, UNIAPI_OK, cookie);
+}
+
+/*
+ * Alerting.request from API
+ *
+ * Q.2971:Call-Control-U 13/39 (U6)
+ * Q.2971:Call-Control-U 17/39 (U9)
+ * Q.2971:Call-Control-N 38/39 (N1)
+ * Q.2971:Call-Control-N 7/39 (N3)
+ */
+static void
+unx_alerting_request(struct call *c, struct uni_msg *m, u_int32_t cookie,
+ enum call_state new_state)
+{
+ struct uni_all *msg;
+ struct uniapi_alerting_request *arg =
+ uni_msg_rptr(m, struct uniapi_alerting_request *);
+
+ if ((msg = UNI_ALLOC()) == NULL) {
+ uni_msg_destroy(m);
+ uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
+ return;
+ }
+
+ if (c->type == CALL_ROOT || c->type == CALL_LEAF) {
+ uni_enq_party(TAILQ_FIRST(&c->parties),
+ SIGP_ALERTING_request, cookie, NULL, NULL);
+ }
+
+ /*
+ * It's not really clear, what happens, if we send another
+ * connid in CALL_PROC and ALERTING
+ */
+ if (!IE_ISGOOD(c->connid) && IE_ISGOOD(arg->alerting.connid))
+ c->connid = arg->alerting.connid;
+
+ msg->u.alerting = arg->alerting;
+ MK_MSG_ORIG(msg, UNI_ALERTING, c->cref, !c->mine);
+ (void)uni_send_output(msg, c->uni);
+ UNI_FREE(msg);
+
+ set_call_state(c, new_state);
+
+ uni_msg_destroy(m);
+
+ uniapi_call_error(c, UNIAPI_OK, cookie);
+}
+
+
+/*
+ * Setup.response from API
+ *
+ * Q.2971:Call-Control-U 13/39 (U6)
+ * Q.2971:Call-Control-U 14/39 (U7)
+ * Q.2971:Call-Control-U 17/39 (U9)
+ * Q.2971:Call-Control-N 39/39 (N1)
+ * Q.2971:Call-Control-N 7/39 (N3)
+ * Q.2971:Call-Control-N 8/39 (N4)
+ */
+static void
+unx_setup_response(struct call *c, struct uni_msg *m, u_int32_t cookie,
+ enum call_state new_state)
+{
+ struct uni_all *msg;
+ struct uniapi_setup_response *arg =
+ uni_msg_rptr(m, struct uniapi_setup_response *);
+ struct party *p;
+
+ if ((msg = UNI_ALLOC()) == NULL) {
+ uni_msg_destroy(m);
+ uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
+ return;
+ }
+
+ if (!IE_ISGOOD(c->connid) && IE_ISGOOD(arg->connect.connid))
+ c->connid = arg->connect.connid;
+
+ if (IE_ISGOOD(arg->connect.epref)) {
+ p = uni_find_partyx(c, arg->connect.epref.epref,
+ !arg->connect.epref.flag);
+ if (p == NULL) {
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
+ UNI_FREE(msg);
+ uni_msg_destroy(m);
+ return;
+ }
+ /* we need to remember that we have sent the CONNECT from this
+ * party because the CONNECT ACK must move only this party
+ * into P7 */
+ p->flags |= PARTY_CONNECT;
+
+ } else if (c->type == CALL_LEAF) {
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
+ UNI_FREE(msg);
+ uni_msg_destroy(m);
+ return;
+ }
+
+ /* inform the parties on the network side */
+ if (c->uni->proto == UNIPROTO_UNI40N && c->type == CALL_LEAF)
+ TAILQ_FOREACH(p, &c->parties, link)
+ uni_enq_party(p, SIGP_SETUP_response, 0, NULL, NULL);
+
+ msg->u.connect = arg->connect;
+ MK_MSG_ORIG(msg, UNI_CONNECT, c->cref, !c->mine);
+ (void)uni_send_output(msg, c->uni);
+ UNI_FREE(msg);
+
+ if (c->uni->proto == UNIPROTO_UNI40U)
+ TIMER_START_CALL(c, t313, c->uni->timer313);
+
+ set_call_state(c, new_state);
+
+ uni_msg_destroy(m);
+
+ uniapi_call_error(c, UNIAPI_OK, cookie);
+}
+
+/*
+ * Setup_complete.request
+ *
+ * Q.2971:Call-Control-N 15/39 (N8)
+ */
+static void
+n8_setup_compl_request(struct call *c, struct uni_msg *m, u_int32_t cookie,
+ enum call_state new_state)
+{
+ struct uni_all *msg;
+ struct uniapi_setup_complete_request *arg =
+ uni_msg_rptr(m, struct uniapi_setup_complete_request *);
+ struct party *p;
+
+ if ((msg = UNI_ALLOC()) == NULL) {
+ uni_msg_destroy(m);
+ uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
+ return;
+ }
+
+ /* inform the parties on the network side */
+ if (c->uni->proto == UNIPROTO_UNI40N &&
+ (c->type == CALL_LEAF || c->type == CALL_ROOT)) {
+ TAILQ_FOREACH(p, &c->parties, link)
+ uni_enq_party(p, SIGP_SETUP_COMPL_request,
+ 0, NULL, NULL);
+ }
+
+ msg->u.connect_ack = arg->connect_ack;
+ MK_MSG_ORIG(msg, UNI_CONNECT_ACK, c->cref, !c->mine);
+ (void)uni_send_output(msg, c->uni);
+ UNI_FREE(msg);
+
+ set_call_state(c, new_state);
+
+ uni_msg_destroy(m);
+
+ uniapi_call_error(c, UNIAPI_OK, cookie);
+}
+
+/*
+ * CONNECT message
+ *
+ * Q.2971:Call-Control-U 7-8/39 (U3)
+ * Q.2971:Call-Control-U 11/39 (U4)
+ * Q.2971:Call-Control-U 37/39 (U1)
+ * Q.2971:Call-Control-N 9-10/39 (N6)
+ * Q.2971:Call-Control-N 14/39 (N7)
+ * Q.2971:Call-Control-N 17/39 (N9)
+ */
+static void
+unx_connect(struct call *c, struct uni_msg *m, struct uni_all *u,
+ enum call_state new_state)
+{
+ struct uni_connect *co = &u->u.connect;
+ struct uniapi_setup_confirm *conf;
+ struct uni_msg *api;
+ struct uni_all *ack;
+ struct party *p;
+
+ conf = ALLOC_API(struct uniapi_setup_confirm, api);
+ if (conf == NULL) {
+ ignore:
+ UNI_FREE(u);
+ uni_msg_destroy(m);
+ return;
+ }
+ if ((ack = UNI_ALLOC()) == NULL) {
+ uni_msg_destroy(api);
+ goto ignore;
+ }
+
+ /*
+ * Analyze message
+ */
+ (void)uni_decode_body(m, u, &c->uni->cx);
+ if (!IE_ISPRESENT(c->connid) && !IE_ISGOOD(co->connid))
+ uni_mandate_ie(c->uni, UNI_IE_CONNID);
+
+ /*
+ * Q.2971: L3MU_01_05 requires the epref to be present.
+ */
+ p = NULL;
+ if (c->msg_setup.bearer.cfg == UNI_BEARER_MP) {
+ if (IE_ISPRESENT(c->msg_setup.epref)) {
+ if (!IE_ISPRESENT(co->epref))
+ uni_mandate_ie(c->uni, UNI_IE_EPREF); \
+
+ if (IE_ISGOOD(co->epref) &&
+ co->epref.flag != 1) {
+ IE_SETERROR(co->epref);
+ UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF,
+ co->epref.h.act, UNI_IERR_BAD);
+ }
+ }
+
+ if (IE_ISGOOD(co->epref)) {
+ p = uni_find_party(c, &co->epref);
+ if (p == NULL) {
+ respond_drop_party_ack(c, &co->epref,
+ UNI_CAUSE_ENDP_INV);
+ uni_msg_destroy(api);
+ UNI_FREE(ack);
+ goto ignore;
+ }
+ }
+ }
+
+ switch (uni_verify(c->uni, u->u.hdr.act)) {
+
+ case VFY_CLR:
+ uni_vfy_collect_ies(c->uni);
+ clear_callD(c);
+ /* FALLTHRU */
+ case VFY_I:
+ uni_msg_destroy(api);
+ UNI_FREE(ack);
+ goto ignore;
+
+ case VFY_RAIM:
+ case VFY_RAI:
+ report:
+ uni_respond_status_verify(c->uni, &u->u.hdr.cref,
+ map_callstate(c->cstate), NULL, 0);
+ uni_msg_destroy(api);
+ UNI_FREE(ack);
+ goto ignore;
+
+ case VFY_RAP:
+ case VFY_RAPU:
+ if (c->type == CALL_ROOT && !IE_ISGOOD(co->epref))
+ goto report;
+ uni_respond_status_verify(c->uni, &u->u.hdr.cref,
+ map_callstate(new_state), NULL, 0);
+ /* FALLTHRU */
+ case VFY_OK:
+ break;
+ }
+
+ if (IE_ISGOOD(co->connid))
+ c->connid = co->connid;
+
+ if (c->cstate == CALLST_U1 || c->cstate == CALLST_N6)
+ TIMER_STOP_CALL(c, t303);
+ else if (c->cstate == CALLST_U3 || c->cstate == CALLST_N9)
+ TIMER_STOP_CALL(c, t310);
+ else if (c->cstate == CALLST_U4 || c->cstate == CALLST_N7) {
+ if(c->type == CALL_P2P)
+ TIMER_STOP_CALL(c, t301);
+ }
+
+ /*
+ * This is sent to the party only on the user side and only
+ * to the one party in the epref (L3MU_05_03).
+ */
+ if (c->uni->proto == UNIPROTO_UNI40U &&
+ (c->type == CALL_LEAF || c->type == CALL_ROOT))
+ uni_enq_party(p, SIGP_CONNECT, 0, NULL, NULL);
+
+ conf->connect.hdr = u->u.hdr;
+ copy_msg_connect(co, &conf->connect);
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_SETUP_confirm, 0, api);
+
+ if (c->uni->proto == UNIPROTO_UNI40U) {
+ /* this is left to the application on the network side */
+ MK_MSG_ORIG(ack, UNI_CONNECT_ACK, c->cref, !c->mine);
+ (void)uni_send_output(ack, c->uni);
+ UNI_FREE(ack);
+ }
+
+ UNI_FREE(u);
+ uni_msg_destroy(m);
+
+ set_call_state(c, new_state);
+}
+
+/*
+ * T313 (Connect) timer tick.
+ *
+ * Q.2971:Call-Control-U 15/39
+ */
+static void
+u8_t313(struct call *c)
+{
+ VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T313 tick",
+ c->cref, c->mine ? "mine" : "his");
+
+ MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_RECOVER);
+ ADD_CAUSE_TIMER(c->uni->cause, "313");
+ clear_callD(c);
+}
+
+/*
+ * CONNECT ACKNOWLEDGE message in U8
+ *
+ * Q.2971:Call-Control-U 15-16/39
+ */
+static void
+u8_connect_ack(struct call *c, struct uni_msg *m, struct uni_all *u,
+ enum call_state new_state)
+{
+ struct uniapi_setup_complete_indication *ind;
+ struct uni_msg *api;
+
+ ind = ALLOC_API(struct uniapi_setup_complete_indication, api);
+ if (ind == NULL) {
+ ignore:
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+ return;
+ }
+
+ /*
+ * Analyze message
+ */
+ (void)uni_decode_body(m, u, &c->uni->cx);
+
+ switch (uni_verify(c->uni, u->u.hdr.act)) {
+
+ case VFY_CLR:
+ uni_vfy_collect_ies(c->uni);
+ clear_callD(c);
+ /* FALLTHRU */
+ case VFY_I:
+ uni_msg_destroy(api);
+ goto ignore;
+
+ case VFY_RAIM:
+ case VFY_RAI:
+ uni_respond_status_verify(c->uni, &u->u.hdr.cref,
+ map_callstate(c->cstate), NULL, 0);
+ uni_msg_destroy(api);
+ goto ignore;
+
+ case VFY_RAP:
+ case VFY_RAPU:
+ uni_respond_status_verify(c->uni, &u->u.hdr.cref,
+ map_callstate(new_state), NULL, 0);
+ /* FALLTHRU */
+ case VFY_OK:
+ break;
+ }
+
+ TIMER_STOP_CALL(c, t313);
+
+ if (c->type == CALL_LEAF) {
+ struct party *p;
+
+ TAILQ_FOREACH(p, &c->parties, link) {
+ if (p->flags & PARTY_CONNECT) {
+ uni_enq_party(p, SIGP_CONNECT_ACK,
+ 0, NULL, NULL);
+ break;
+ }
+ }
+ }
+
+ ind->connect_ack.hdr = u->u.hdr;
+ copy_msg_connect_ack(&u->u.connect_ack, &ind->connect_ack);
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_SETUP_COMPLETE_indication, 0, api);
+
+ UNI_FREE(u);
+ uni_msg_destroy(m);
+
+ set_call_state(c, new_state);
+}
+
+/*
+ * CONNECT ACKNOWLEDGE message in N10
+ *
+ * Q.2971:Call-Control-N 18/39
+ */
+static void
+n10_connect_ack(struct call *c, struct uni_msg *m, struct uni_all *u)
+{
+ /*
+ * Analyze message
+ */
+ (void)uni_decode_body(m, u, &c->uni->cx);
+
+ switch (uni_verify(c->uni, u->u.hdr.act)) {
+
+ case VFY_CLR:
+ uni_vfy_collect_ies(c->uni);
+ clear_callD(c);
+ /* FALLTHRU */
+ case VFY_I:
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+ return;
+
+ case VFY_RAIM:
+ case VFY_RAI:
+ case VFY_RAP:
+ case VFY_RAPU:
+ uni_respond_status_verify(c->uni, &u->u.hdr.cref,
+ map_callstate(c->cstate), NULL, 0);
+ /* FALLTHRU */
+ case VFY_OK:
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+ return;
+ }
+}
+
+/*
+ * Release.response in U6 or U12.
+ *
+ * Q.2971:Call-Control-U 12/39 (U6)
+ * Q.2971:Call-Control-U 30/39 (U12)
+ * Q.2971:Call-Control-N 6/39 (N1)
+ * Q.2971:Call-Control-N 29/39 (N11)
+ */
+static void
+unx_release_response(struct call *c, struct uni_msg *m, u_int32_t cookie)
+{
+ struct party *p;
+ struct uni_all *msg;
+ struct uniapi_release_response *arg =
+ uni_msg_rptr(m, struct uniapi_release_response *);
+
+ if ((msg = UNI_ALLOC()) == NULL) {
+ uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
+ uni_msg_destroy(m);
+ return;
+ }
+
+ if (c->cstate == CALLST_U6 || c->cstate == CALLST_N1) {
+ if (c->type == CALL_ROOT || c->type == CALL_LEAF) {
+ TAILQ_FOREACH(p, &c->parties, link)
+ uni_enq_party(p, SIGP_RELEASE_response,
+ cookie, NULL, NULL);
+ }
+ }
+ msg->u.release_compl = arg->release_compl;
+ MK_MSG_ORIG(msg, UNI_RELEASE_COMPL, c->cref, !c->mine);
+ (void)uni_send_output(msg, c->uni);
+ UNI_FREE(msg);
+
+ uni_msg_destroy(m);
+
+ uniapi_call_error(c, UNIAPI_OK, cookie);
+
+ uni_destroy_call(c, 0);
+}
+
+/*
+ * Got a RELEASE COMPLETE in any state expect U0
+ *
+ * Q.2971:Call-Control-U 25/39
+ * Q.2971:Call-Control-N 26/39
+ *
+ * This is also called from the restart processes.
+ */
+void
+uni_release_compl(struct call *c, struct uni_all *u)
+{
+ struct uni_msg *api;
+ struct uniapi_release_confirm *conf;
+ struct party *p;
+ u_int i, j;
+
+ if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) == NULL)
+ return;
+
+ reset_all_timers(c);
+ if (c->type == CALL_ROOT || c->type == CALL_LEAF) {
+ TAILQ_FOREACH(p, &c->parties, link)
+ uni_enq_party(p, SIGP_RELEASE_COMPL, 0, NULL, NULL);
+ /* YYY optional call reoffering 10.3.3/10.3.4 */
+ }
+ conf->release.hdr = u->u.hdr;
+
+ for (i = j = 0; i < 2; i++)
+ if (IE_ISGOOD(u->u.release_compl.cause[i]))
+ conf->release.cause[j++] = u->u.release_compl.cause[i];
+ for (i = j = 0; i < UNI_NUM_IE_GIT; i++)
+ if (IE_ISGOOD(u->u.release_compl.git[i]))
+ conf->release.git[j++] = u->u.release_compl.git[i];
+ if (IE_ISGOOD(u->u.release_compl.uu))
+ conf->release.uu = u->u.release_compl.uu;
+ if (IE_ISGOOD(u->u.release_compl.crankback))
+ conf->release.crankback = u->u.release_compl.crankback;
+
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_RELEASE_confirm, 0, api);
+
+ uni_destroy_call(c, 0);
+}
+static void
+unx_release_compl(struct call *c, struct uni_msg *m, struct uni_all *u)
+{
+
+ (void)uni_decode_body(m, u, &c->uni->cx);
+ (void)uni_verify(c->uni, u->u.hdr.act); /* no point :-) */
+
+ uni_release_compl(c, u);
+
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+}
+
+/*
+ * Got a RELEASE COMPLETE in any state expect U0 and U11
+ *
+ * Q.2971:Call-Control-U 25/39
+ * Q.2971:Call-Control-N 26/39
+ */
+static void
+unx_release(struct call *c, struct uni_msg *m, struct uni_all *u,
+ enum call_state new_state)
+{
+ struct uniapi_release_indication *ind;
+ struct uni_msg *api;
+
+ if ((ind = ALLOC_API(struct uniapi_release_indication, api)) == NULL) {
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+ return;
+ }
+
+ (void)uni_decode_body(m, u, &c->uni->cx);
+ (void)uni_verify(c->uni, u->u.hdr.act); /* no point :-) */
+
+ reset_all_timers(c);
+ if (c->type == CALL_ROOT || c->type == CALL_LEAF) {
+ struct party *p;
+
+ TAILQ_FOREACH(p, &c->parties, link)
+ uni_enq_party(p, SIGP_RELEASE, 0, NULL, NULL);
+ /* YYY optional call reoffering 10.3.3/10.3.4 */
+ }
+ if (c->cstate != new_state) {
+ /*
+ * According to Q.2971 we should send a 2nd
+ * Release.indication.
+ * According to Q.2931 the recipte of a RELEASE in U12/N11
+ * is illegal.
+ * According to us make it legal, but don't send a 2nd
+ * indication.
+ */
+ ind->release.hdr = u->u.hdr;
+ copy_msg_release(&u->u.release, &ind->release);
+
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_RELEASE_indication, 0, api);
+ } else
+ uni_msg_destroy(api);
+
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+
+ set_call_state(c, new_state);
+}
+
+/*
+ * Got RELEASE in U11 or N12
+ *
+ * Q.2971:Call-Control-U 28/39
+ * Q.2971:Call-Control-N 30/39
+ */
+static void
+u11n12_release(struct call *c, struct uni_msg *m, struct uni_all *u)
+{
+ struct uniapi_release_confirm *conf;
+ struct uni_msg *api;
+
+ if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) == NULL) {
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+ return;
+ }
+
+ (void)uni_decode_body(m, u, &c->uni->cx);
+ (void)uni_verify(c->uni, u->u.hdr.act); /* no point :-) */
+
+ TIMER_STOP_CALL(c, t308);
+
+ conf->release.hdr = u->u.hdr;
+ copy_msg_release(&u->u.release, &conf->release);
+
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_RELEASE_confirm, 0, api);
+
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+
+ uni_destroy_call(c, 0);
+}
+
+/*
+ * NOTIFY message
+ *
+ * Q.2971:Call-Control-U 18/39
+ * Q.2971:Call-Control-N 19/39
+ */
+static void
+unx_notify(struct call *c, struct uni_msg *m, struct uni_all *u)
+{
+ struct uniapi_notify_indication *ind;
+ struct uni_msg *api;
+ struct party *p = NULL;
+
+ if ((ind = ALLOC_API(struct uniapi_notify_indication, api)) == NULL) {
+ ignore:
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+ return;
+ }
+
+ /*
+ * Analyze message
+ */
+ (void)uni_decode_body(m, u, &c->uni->cx);
+ MANDATE_IE(c->uni, u->u.notify.notify, UNI_IE_NOTIFY);
+
+ if (IE_ISGOOD(u->u.notify.epref)) {
+ if ((p = uni_find_party(c, &u->u.notify.epref)) == NULL) {
+ respond_drop_party_ack(c, &u->u.notify.epref,
+ UNI_CAUSE_ENDP_INV);
+ uni_msg_destroy(api);
+ goto ignore;
+ }
+ }
+
+ switch (uni_verify(c->uni, u->u.hdr.act)) {
+
+ case VFY_CLR:
+ uni_msg_destroy(api);
+ uni_vfy_collect_ies(c->uni);
+ clear_callD(c);
+ goto ignore;
+
+ case VFY_RAIM:
+ case VFY_RAI:
+ uni_respond_status_verify(c->uni, &u->u.hdr.cref,
+ map_callstate(c->cstate), &u->u.notify.epref,
+ p ? p->state : 0);
+ /* FALLTHRU */
+ case VFY_I:
+ uni_msg_destroy(api);
+ goto ignore;
+
+ case VFY_RAP:
+ case VFY_RAPU:
+ uni_respond_status_verify(c->uni, &u->u.hdr.cref,
+ map_callstate(c->cstate), &u->u.notify.epref,
+ p ? p->state : 0);
+ case VFY_OK:
+ /* FALLTHRU */
+ break;
+ }
+
+ ind->notify.hdr = u->u.hdr;
+ copy_msg_notify(&u->u.notify, &ind->notify);
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_NOTIFY_indication, 0, api);
+
+ UNI_FREE(u);
+ uni_msg_destroy(m);
+}
+
+/*
+ * Notify.request from user
+ *
+ * Q.2971:Call-Control-U 18/39
+ * Q.2971:Call-Control-N 19/39
+ */
+static void
+unx_notify_request(struct call *c, struct uni_msg *m, u_int32_t cookie)
+{
+ struct uni_all *msg;
+ struct uniapi_notify_request *arg =
+ uni_msg_rptr(m, struct uniapi_notify_request *);
+
+ if ((msg = UNI_ALLOC()) == NULL) {
+ uni_msg_destroy(m);
+ uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
+ return;
+ }
+
+ msg->u.notify = arg->notify;
+ MK_MSG_ORIG(msg, UNI_NOTIFY, c->cref, !c->mine);
+ (void)uni_send_output(msg, c->uni);
+ UNI_FREE(msg);
+
+ uni_msg_destroy(m);
+
+ uniapi_call_error(c, UNIAPI_OK, cookie);
+}
+
+/**********************************************************************/
+
+/*
+ * Release.request from API in any state except U11, U12, N11, N12
+ *
+ * Q.2971:Call-Control-U 27/39
+ * Q.2971:Call-Control-N 28/39
+ */
+static void
+unx_release_request(struct call *c, struct uni_msg *m, u_int32_t cookie,
+ enum call_state new_state)
+{
+ struct uni_all *msg;
+ struct uniapi_release_request *arg =
+ uni_msg_rptr(m, struct uniapi_release_request *);
+ struct party *p;
+
+ if ((msg = UNI_ALLOC()) == NULL) {
+ uni_msg_destroy(m);
+ uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
+ return;
+ }
+
+ reset_all_timers(c);
+
+ if (c->type == CALL_LEAF || c->type == CALL_ROOT) {
+ TAILQ_FOREACH(p, &c->parties, link) {
+ uni_enq_party(p, SIGP_RELEASE_request, cookie,
+ NULL, NULL);
+ }
+ }
+
+ c->msg_release = arg->release;
+ if (!IE_ISPRESENT(c->msg_release.cause[0]) &&
+ !IE_ISPRESENT(c->msg_release.cause[1]))
+ MK_IE_CAUSE(c->msg_release.cause[0], UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_UNSPEC);
+
+ msg->u.release = c->msg_release;
+ MK_MSG_ORIG(msg, UNI_RELEASE, c->cref, !c->mine);
+ (void)uni_send_output(msg, c->uni);
+ UNI_FREE(msg);
+
+ TIMER_START_CALL(c, t308, c->uni->timer308);
+ c->cnt308 = 0;
+
+ set_call_state(c, new_state);
+
+ uni_msg_destroy(m);
+
+ uniapi_call_error(c, UNIAPI_OK, cookie);
+}
+
+/*
+ * Message with unknown EPREF - send a drop party according to 9.5.3.2.3a)
+ */
+static void
+respond_drop_party_ack(struct call *c, struct uni_ie_epref *epref,
+ u_int cause)
+{
+ struct uni_all *msg;
+
+ if ((msg = UNI_ALLOC()) == NULL)
+ return;
+
+ MK_MSG_ORIG(msg, UNI_DROP_PARTY_ACK, c->cref, !c->mine);
+ MK_IE_EPREF(msg->u.drop_party_ack.epref, epref->epref, !epref->flag);
+ MK_IE_CAUSE(msg->u.drop_party_ack.cause, UNI_CAUSE_LOC_USER, cause);
+ (void)uni_send_output(msg, c->uni);
+ UNI_FREE(msg);
+}
+
+/*
+ * T308 (RELEASE) timer
+ *
+ * Q.2971:Call-Control-U 28/39
+ * Q.2971:Call-Control-N 30/39
+ */
+static void
+u11n12_t308(struct call *c)
+{
+ struct uni_all *msg;
+ struct uni_msg *api;
+ struct uniapi_release_confirm *conf;
+
+ VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T308 tick %d",
+ c->cref, c->mine ? "mine" : "his", c->cnt308 + 1);
+
+ if (++c->cnt308 < c->uni->init308) {
+ if ((msg = UNI_ALLOC()) != NULL) {
+ msg->u.release = c->msg_release;
+ MK_MSG_ORIG(msg, UNI_RELEASE, c->cref, !c->mine);
+ if (!IE_ISPRESENT(msg->u.release.cause[1])) {
+ MK_IE_CAUSE(msg->u.release.cause[1],
+ UNI_CAUSE_LOC_USER, UNI_CAUSE_RECOVER);
+ ADD_CAUSE_TIMER(msg->u.release.cause[1], "308");
+ }
+ (void)uni_send_output(msg, c->uni);
+ UNI_FREE(msg);
+ }
+ TIMER_START_CALL(c, t308, c->uni->timer308);
+ return;
+ }
+
+ /*
+ * Send indication to API
+ */
+ if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) != NULL) {
+ conf->release.hdr.cref.cref = c->cref;
+ conf->release.hdr.cref.flag = c->mine;
+ conf->release.hdr.act = UNI_MSGACT_DEFAULT;
+ MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_RECOVER);
+ ADD_CAUSE_TIMER(conf->release.cause[0], "308");
+
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_RELEASE_confirm, 0, api);
+ }
+
+ uni_destroy_call(c, 0);
+}
+/**********************************************************************/
+
+/*
+ * STATUS in U11/U12
+ *
+ * Q.2971:Call-Control-U 29/39 (U11)
+ * Q.2971:Call-Control-U 30/39 (U12)
+ * Q.2971:Call-Control-N 29/39 (N11)
+ * Q.2971:Call-Control-N 31/39 (N12)
+ */
+static void
+un11un12_status(struct call *c, struct uni_msg *m, struct uni_all *u)
+{
+ enum call_state ns;
+ struct uniapi_release_confirm *conf;
+ struct uni_msg *api;
+ struct party *p;
+ struct uniapi_status_indication *stat;
+
+ /*
+ * Analyze message
+ */
+ (void)uni_decode_body(m, u, &c->uni->cx);
+ MANDATE_IE(c->uni, u->u.status.callstate, UNI_IE_CALLSTATE);
+ MANDATE_IE(c->uni, u->u.status.cause, UNI_IE_CAUSE);
+
+ ns = c->cstate;
+ if (IE_ISGOOD(u->u.status.callstate) &&
+ u->u.status.callstate.state == UNI_CALLSTATE_U0)
+ ns = CALLST_NULL;
+
+ p = NULL;
+ if (IE_ISGOOD(u->u.status.epref))
+ p = uni_find_party(c, &u->u.status.epref);
+
+ switch (uni_verify(c->uni, u->u.hdr.act)) {
+
+ case VFY_CLR:
+ uni_vfy_collect_ies(c->uni);
+ clear_callD(c);
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+ return;
+
+ case VFY_RAIM:
+ case VFY_RAI:
+ case VFY_RAP:
+ case VFY_RAPU:
+ uni_respond_status_verify(c->uni, &u->u.hdr.cref,
+ map_callstate(ns), &u->u.status.epref,
+ p ? p->state : UNI_EPSTATE_NULL);
+ case VFY_I:
+ case VFY_OK:
+ break;
+ }
+
+ if (ns == c->cstate) {
+ /*
+ * Inform API
+ */
+ stat = ALLOC_API(struct uniapi_status_indication, api);
+ if (stat != NULL) {
+ stat->cref = u->u.hdr.cref;
+ stat->my_state = map_callstate(c->cstate);
+ stat->his_state = u->u.status.callstate;
+ stat->his_cause = u->u.status.cause;
+ stat->epref = u->u.status.epref;
+ stat->epstate = u->u.status.epstate;
+ stat->my_cause = 0;
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_STATUS_indication, 0, api);
+ }
+
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+
+ return;
+ }
+
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+
+ /*
+ * Send indication to API
+ */
+ if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) != NULL) {
+ conf->release.hdr.cref.cref = c->cref;
+ conf->release.hdr.cref.flag = c->mine;
+ conf->release.hdr.act = UNI_MSGACT_DEFAULT;
+ MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_MSG_INCOMP);
+ ADD_CAUSE_MTYPE(conf->release.cause[0], UNI_STATUS);
+
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_RELEASE_confirm, 0, api);
+ }
+
+ uni_destroy_call(c, 0);
+}
+
+static int
+status_enq_filter(struct sig *sig, void *arg)
+{
+ return (sig->type == SIG_CALL &&
+ (struct call *)arg == sig->call &&
+ sig->sig == SIGC_SEND_STATUS_ENQ);
+}
+
+/*
+ * STATUS in any state except U0/U11/U12 N0/N11/N12
+ *
+ * Q.2971:Call-Control-U 32/39
+ * Q.2971:Call-Control-N 33/39
+ */
+static void
+unx_status(struct call *c, struct uni_msg *m, struct uni_all *u)
+{
+ struct uniapi_status_indication *stat;
+ struct uniapi_release_confirm *conf;
+ enum call_state ns;
+ struct uni_msg *api;
+ struct party *p;
+
+ /*
+ * Analyze message
+ */
+ (void)uni_decode_body(m, u, &c->uni->cx);
+ MANDATE_IE(c->uni, u->u.status.callstate, UNI_IE_CALLSTATE);
+ MANDATE_IE(c->uni, u->u.status.cause, UNI_IE_CAUSE);
+
+ ns = c->cstate;
+ if (IE_ISGOOD(u->u.status.callstate))
+ ns = state_compat(c, u->u.status.callstate.state);
+
+ p = NULL;
+ if (IE_ISGOOD(u->u.status.epref)) {
+ p = uni_find_party(c, &u->u.status.epref);
+ MANDATE_IE(c->uni, u->u.status.epstate, UNI_IE_EPSTATE);
+ }
+
+ switch (uni_verify(c->uni, u->u.hdr.act)) {
+
+ case VFY_CLR:
+ uni_vfy_collect_ies(c->uni);
+ clear_callD(c);
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+ return;
+
+ case VFY_RAIM:
+ case VFY_RAI:
+ case VFY_RAP:
+ case VFY_RAPU:
+ uni_respond_status_verify(c->uni, &u->u.hdr.cref,
+ map_callstate(ns), &u->u.notify.epref,
+ p ? p->state : UNI_EPSTATE_NULL);
+ /* FALLTHRU */
+ case VFY_I:
+ case VFY_OK:
+ break;
+ }
+
+ if (u->u.status.callstate.state == UNI_CALLSTATE_U0) {
+ /* release_complete */
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+
+ if (c->type == CALL_LEAF || c->type == CALL_ROOT) {
+ TAILQ_FOREACH(p, &c->parties, link)
+ uni_enq_party(p, SIGP_RELEASE_COMPL,
+ 0, NULL, NULL);
+ }
+ /*
+ * Send indication to API
+ */
+ conf = ALLOC_API(struct uniapi_release_confirm, api);
+ if (conf != NULL) {
+ conf->release.hdr.cref.cref = c->cref;
+ conf->release.hdr.cref.flag = c->mine;
+ conf->release.hdr.act = UNI_MSGACT_DEFAULT;
+ MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_MSG_INCOMP);
+ ADD_CAUSE_MTYPE(conf->release.cause[0], UNI_STATUS);
+
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_RELEASE_confirm, 0, api);
+ }
+ uni_destroy_call(c, 0);
+ return;
+ }
+
+ if (IE_ISGOOD(u->u.status.cause) &&
+ u->u.status.cause.cause == UNI_CAUSE_STATUS) {
+ c->se_active = 0;
+ TIMER_STOP_CALL(c, t322);
+ uni_undel(c->uni, status_enq_filter, c);
+ }
+
+ /*
+ * Inform API
+ */
+ if ((stat = ALLOC_API(struct uniapi_status_indication, api)) != NULL) {
+ stat->cref = u->u.hdr.cref;
+ stat->my_state = map_callstate(c->cstate);
+ stat->his_state = u->u.status.callstate;
+ stat->his_cause = u->u.status.cause;
+ stat->epref = u->u.status.epref;
+ stat->epstate = u->u.status.epstate;
+ }
+
+ if (ns == c->cstate) {
+ /* compatible or recovered */
+ if (p != NULL)
+ uni_enq_party(p, SIGP_STATUS, 0, m, u);
+ else {
+ if (IE_ISGOOD(u->u.status.epref) &&
+ (!IE_ISGOOD(u->u.status.epstate) ||
+ u->u.status.epstate.state != UNI_EPSTATE_NULL))
+ respond_drop_party_ack(c, &u->u.status.epref,
+ UNI_CAUSE_MSG_INCOMP);
+
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+ }
+ if (stat != NULL) {
+ stat->my_cause = 0;
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_STATUS_indication, 0, api);
+ }
+
+ return;
+ }
+
+ /* incompatible */
+ if (stat != NULL) {
+ stat->my_cause = UNI_CAUSE_MSG_INCOMP;
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_STATUS_indication, 0, api);
+ }
+
+ MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_MSG_INCOMP);
+
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+
+ clear_callD(c);
+}
+
+/*
+ * Enquiry peer status
+ *
+ * Q.2971:Call-Control-U 31/39
+ * Q.2971:Call-Control-N 32/39
+ */
+static void
+unx_status_enquiry_request(struct call *c, struct uni_msg *msg, u_int32_t cookie)
+{
+ struct uniapi_status_enquiry_request *arg =
+ uni_msg_rptr(msg, struct uniapi_status_enquiry_request *);
+ struct party *p;
+ struct uni_all *stat;
+
+ if (c->se_active) {
+ /* This case is not handled in the SDLs */
+ uniapi_call_error(c, UNIAPI_ERROR_BUSY, cookie);
+ uni_msg_destroy(msg);
+ return;
+ }
+ if ((c->type == CALL_ROOT || c->type == CALL_LEAF) &&
+ IE_ISGOOD(arg->epref)) {
+ if ((p = uni_find_partyx(c, arg->epref.epref, !arg->epref.flag))
+ == NULL) {
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
+ uni_msg_destroy(msg);
+ return;
+ }
+ uni_msg_destroy(msg);
+ uni_enq_party(p, SIGP_STATUS_ENQUIRY_request, cookie,
+ NULL, NULL);
+ return;
+ }
+ if ((stat = UNI_ALLOC()) == NULL) {
+ uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
+ uni_msg_destroy(msg);
+ return;
+ }
+ memset(&c->stat_epref, 0, sizeof(c->stat_epref));
+ MK_MSG_ORIG(stat, UNI_STATUS_ENQ, c->cref, !c->mine);
+ (void)uni_send_output(stat, c->uni);
+ UNI_FREE(stat);
+
+ TIMER_START_CALL(c, t322, c->uni->timer322);
+ c->cnt322 = 0;
+ c->se_active = 1;
+
+ uniapi_call_error(c, UNIAPI_OK, cookie);
+}
+
+/*
+ * T322 tick
+ *
+ * Q.2971:Call-Control-U 34/39
+ * Q.2971:Call-Control-N 35/39
+ */
+static void
+unx_t322(struct call *c)
+{
+ struct uni_all *stat;
+
+ VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T322 tick %d",
+ c->cref, c->mine ? "mine" : "his", c->cnt322 + 1);
+
+ if (++c->cnt322 < c->uni->init322) {
+ if ((stat = UNI_ALLOC()) != NULL) {
+ MK_MSG_ORIG(stat, UNI_STATUS_ENQ, c->cref, !c->mine);
+ stat->u.status_enq.epref = c->stat_epref;
+ (void)uni_send_output(stat, c->uni);
+ UNI_FREE(stat);
+ }
+ TIMER_START_CALL(c, t322, c->uni->timer322);
+ return;
+ }
+ c->se_active = 0;
+
+ MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_RECOVER);
+ ADD_CAUSE_TIMER(c->uni->cause, "322");
+
+ clear_callD(c);
+}
+
+/*
+ * STATUS ENQUIRY message
+ *
+ * Q.2971:Call-Control-U 31/39
+ * Q.2971:Call-Control-N 32/39
+ */
+static void
+unx_status_enq(struct call *c, struct uni_msg *m, struct uni_all *u)
+{
+ struct party *p = NULL;
+ u_int epref, flag;
+
+ /*
+ * Analyze message
+ */
+ (void)uni_decode_body(m, u, &c->uni->cx);
+
+ switch (uni_verify(c->uni, u->u.hdr.act)) {
+
+ case VFY_CLR:
+ uni_vfy_collect_ies(c->uni);
+ clear_callD(c);
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+ return;
+
+ case VFY_RAIM:
+ case VFY_RAI:
+ case VFY_RAP:
+ case VFY_RAPU:
+ case VFY_I:
+ case VFY_OK:
+ break;
+ }
+
+ uni_msg_destroy(m);
+
+ if ((c->type == CALL_ROOT || c->type == CALL_LEAF) &&
+ IE_ISGOOD(u->u.status_enq.epref)) {
+ p = uni_find_party(c, &u->u.status_enq.epref);
+
+ epref = u->u.status_enq.epref.epref;
+ flag = u->u.status_enq.epref.flag;
+ memset(u, 0, sizeof(*u));
+ MK_IE_EPREF(u->u.status.epref, epref, !flag);
+
+ if (p != NULL)
+ MK_IE_EPSTATE(u->u.status.epstate, p->state);
+ else
+ MK_IE_EPSTATE(u->u.status.epstate, UNI_EPSTATE_NULL);
+ } else
+ memset(u, 0, sizeof(*u));
+
+
+ MK_MSG_ORIG(u, UNI_STATUS, c->cref, !c->mine);
+ MK_IE_CALLSTATE(u->u.status.callstate, map_callstate(c->cstate));
+ MK_IE_CAUSE(u->u.status.cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_STATUS);
+ (void)uni_send_output(u, c->uni);
+ UNI_FREE(u);
+}
+
+/**********************************************************************/
+
+/*
+ * Link-release.indication from SAAL in state U10 or N10.
+ *
+ * Q.2971:Call-Control-U 19/39
+ * Q.2971:Call-Control-N 20/39
+ */
+static void
+un10_link_release_indication(struct call *c)
+{
+ struct party *p;
+
+ if (c->type == CALL_LEAF || c->type == CALL_ROOT)
+ TAILQ_FOREACH(p, &c->parties, link) {
+ if (p->state != UNI_EPSTATE_ACTIVE)
+ uni_enq_party(p, SIGP_RELEASE_COMPL,
+ 0, NULL, NULL);
+ }
+
+ uni_enq_coord(c->uni, SIGO_LINK_ESTABLISH_request, 0, NULL);
+}
+
+/*
+ * Link-release.indication from SAAL in all state except U10 and N10.
+ *
+ * Q.2971:Call-Control-U 36/39
+ * Q.2971:Call-Control-N 37/39
+ */
+static void
+unx_link_release_indication(struct call *c)
+{
+ struct uniapi_release_confirm *conf;
+ struct uni_msg *api;
+ struct party *p;
+
+ if (c->type == CALL_LEAF || c->type == CALL_ROOT)
+ TAILQ_FOREACH(p, &c->parties, link)
+ uni_enq_party(p, SIGP_RELEASE_COMPL, 0, NULL, NULL);
+
+ if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) != NULL) {
+ conf->release.hdr.cref.cref = c->cref;
+ conf->release.hdr.cref.flag = c->mine;
+ conf->release.hdr.act = UNI_MSGACT_DEFAULT;
+ MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_DST_OOO);
+
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_RELEASE_confirm, 0, api);
+ }
+
+ uni_destroy_call(c, 0);
+}
+
+/*
+ * Failed to establish SAAL link. Can happen only in U10 or N10.
+ *
+ * Q.2971:Call-Control-U 19/39
+ * Q.2971:Call-Control-N 20/39
+ */
+static void
+un10_link_establish_error_indication(struct call *c)
+{
+ struct party *p;
+ struct uni_msg *api;
+ struct uniapi_release_confirm *conf;
+
+ if (c->type == CALL_LEAF || c->type == CALL_ROOT)
+ TAILQ_FOREACH(p, &c->parties, link)
+ uni_enq_party(p, SIGP_RELEASE_COMPL, 0, NULL, NULL);
+
+ if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) != NULL) {
+ conf->release.hdr.cref.cref = c->cref;
+ conf->release.hdr.cref.flag = c->mine;
+ conf->release.hdr.act = UNI_MSGACT_DEFAULT;
+ MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_DST_OOO);
+
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_RELEASE_confirm, 0, api);
+ }
+
+ uni_destroy_call(c, 0);
+}
+
+/*
+ * Issue a STATUS ENQUIRY of we are not busy
+ *
+ * Q.2971: Call-Control-U: 34/39
+ * Q.2971: Call-Control-N: 34/39
+ */
+static void
+call_se(struct call *c)
+{
+ struct uni_all *stat;
+
+ c->cnt322 = 0;
+ if (c->se_active)
+ return;
+
+ memset(&c->stat_epref, 0, sizeof(c->stat_epref));
+ if ((stat = UNI_ALLOC()) != NULL) {
+ MK_MSG_ORIG(stat, UNI_STATUS_ENQ, c->cref, !c->mine);
+ (void)uni_send_output(stat, c->uni);
+ UNI_FREE(stat);
+ }
+
+ TIMER_START_CALL(c, t322, c->uni->timer322);
+ c->se_active = 1;
+}
+
+/*
+ * Link-establish.indication in U10
+ *
+ * Q.2971:Call-Control-U 19-20/39
+ * Q.2971:Call-Control-N 20-22/39
+ */
+static void
+un10_link_establish_indication(struct call *c)
+{
+ int act = 0;
+ struct party *p;
+
+ if (c->type == CALL_ROOT || c->type == CALL_LEAF) {
+ TAILQ_FOREACH(p, &c->parties, link)
+ if (p->state == UNI_EPSTATE_ACTIVE) {
+ act = 1;
+ uni_enq_party(p, SIGP_STATUS_ENQUIRY_request,
+ 0, NULL, NULL);
+ }
+ if (act)
+ return;
+ }
+ call_se(c);
+}
+
+/*
+ * Link-establish.indication in NOT U10/U11/U12 N10/N11/N12
+ *
+ * Q.2971:Call-Control-U 36/39
+ * Q.2971:Call-Control-N 37/39
+ */
+static void
+unx_link_establish_indication(struct call *c)
+{
+ call_se(c);
+}
+
+/*
+ * Link-establish.confirm in U10 or N10
+ *
+ * Q.2971:Call-Control-U 19/39
+ * Q.2971:Call-Control-N 20/39
+ */
+static void
+un10_link_establish_confirm(struct call *c)
+{
+ struct party *p;
+
+ if (c->type == CALL_ROOT || c->type == CALL_LEAF) {
+ TAILQ_FOREACH(p, &c->parties, link)
+ uni_enq_party(p, SIGP_STATUS_ENQUIRY_request,
+ 0, NULL, NULL);
+ return;
+ }
+
+ call_se(c);
+}
+
+/*
+ * STATUS ENQ from party
+ *
+ * Q.2971:Call-Control-U 21/39
+ * Q.2971:Call-Control-U 25/39
+ */
+static void
+unx_send_party_status_enq(struct call *c, struct uni_all *u)
+{
+ if (c->se_active) {
+ uni_delenq_sig(c->uni, SIG_CALL, c, NULL,
+ SIGC_SEND_STATUS_ENQ, 0, NULL, u);
+ return;
+ }
+
+ c->stat_epref = u->u.status_enq.epref;
+ (void)uni_send_output(u, c->uni);
+ UNI_FREE(u);
+
+ TIMER_START_CALL(c, t322, c->uni->timer322);
+ c->se_active = 1;
+}
+
+/**********************************************************************/
+
+static void
+make_drop_cause(struct call *c, struct uni_ie_cause *cause)
+{
+
+ if (!IE_ISGOOD(*cause)) {
+ /* 9.5.7.1 paragraph 2 */
+ if (IE_ISPRESENT(*cause))
+ MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_IE_INV);
+ else
+ MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_MANDAT);
+ c->uni->cause.u.ie.len = 1;
+ c->uni->cause.u.ie.ie[0] = UNI_IE_CAUSE;
+ c->uni->cause.h.present |= UNI_CAUSE_IE_P;
+
+ } else if (!IE_ISGOOD(c->uni->cause))
+ c->uni->cause = *cause;
+}
+
+/*
+ * Drop-party.indication from Party-Control in any state.
+ *
+ * Q.2971:Call-Control-U 23/39
+ */
+static void
+ux_drop_party_indication(struct call *c, struct uni_msg *api)
+{
+ struct uniapi_drop_party_indication *drop =
+ uni_msg_rptr(api, struct uniapi_drop_party_indication *);
+
+ if (uni_party_act_count(c, 2) == 0) {
+ if (c->cstate != CALLST_U11) {
+ make_drop_cause(c, &drop->drop.cause);
+ clear_callD(c);
+ }
+ uni_msg_destroy(api);
+ return;
+ }
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_DROP_PARTY_indication, 0, api);
+}
+
+/*
+ * Drop-party.indication from Party-Control in any state.
+ *
+ * Q.2971:Call-Control-N 23/39
+ */
+static void
+nx_drop_party_indication(struct call *c, struct uni_msg *api)
+{
+ struct uniapi_drop_party_indication *drop =
+ uni_msg_rptr(api, struct uniapi_drop_party_indication *);
+
+ if (uni_party_act_count(c, 0) == 0) {
+ if (uni_party_act_count(c, 1) == 0) {
+ if (c->cstate != CALLST_U11) {
+ make_drop_cause(c, &drop->drop.cause);
+ clear_callD(c);
+ }
+ uni_msg_destroy(api);
+ } else {
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_DROP_PARTY_indication, 0, api);
+ set_call_state(c, CALLST_N7);
+ }
+ } else {
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_DROP_PARTY_indication, 0, api);
+ }
+}
+
+/*
+ * Drop-party-ack.indication from Party-Control in any state.
+ *
+ * Q.2971:Call-Control-U 23/39
+ */
+static void
+ux_drop_party_ack_indication(struct call *c, struct uni_msg *api)
+{
+ struct uniapi_drop_party_ack_indication *drop =
+ uni_msg_rptr(api, struct uniapi_drop_party_ack_indication *);
+
+ if (uni_party_act_count(c, 2) == 0) {
+ if (c->cstate != CALLST_U11) {
+ make_drop_cause(c, &drop->drop.cause);
+ clear_callD(c);
+ }
+ uni_msg_destroy(api);
+ return;
+ }
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_DROP_PARTY_ACK_indication, 0, api);
+}
+
+/*
+ * Drop-party-ack.indication from Party-Control in any state.
+ *
+ * Q.2971:Call-Control-N 23/39
+ */
+static void
+nx_drop_party_ack_indication(struct call *c, struct uni_msg *api)
+{
+ struct uniapi_drop_party_ack_indication *drop =
+ uni_msg_rptr(api, struct uniapi_drop_party_ack_indication *);
+
+ if (uni_party_act_count(c, 0) == 0) {
+ if (uni_party_act_count(c, 1) == 0) {
+ if (c->cstate != CALLST_U11) {
+ make_drop_cause(c, &drop->drop.cause);
+ clear_callD(c);
+ }
+ uni_msg_destroy(api);
+ } else {
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_DROP_PARTY_ACK_indication, 0, api);
+ set_call_state(c, CALLST_N7);
+ }
+ } else {
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_DROP_PARTY_ACK_indication, 0, api);
+ }
+}
+
+/*
+ * Add-party-rej.indication from Party-Control in any state.
+ *
+ * Q.2971:Call-Control-U 23/39
+ */
+static void
+ux_add_party_rej_indication(struct call *c, struct uni_msg *api)
+{
+ struct uniapi_add_party_rej_indication *rej =
+ uni_msg_rptr(api, struct uniapi_add_party_rej_indication *);
+
+ if (uni_party_act_count(c, 2) == 0) {
+ if (c->cstate != CALLST_U11) {
+ make_drop_cause(c, &rej->rej.cause);
+ clear_callD(c);
+ }
+ uni_msg_destroy(api);
+ return;
+ }
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_ADD_PARTY_REJ_indication, 0, api);
+}
+
+/*
+ * Add-party-rej.indication from Party-Control in any state.
+ *
+ * Q.2971:Call-Control-N 23/39
+ */
+static void
+nx_add_party_rej_indication(struct call *c, struct uni_msg *api)
+{
+ struct uniapi_add_party_rej_indication *rej =
+ uni_msg_rptr(api, struct uniapi_add_party_rej_indication *);
+
+ if (uni_party_act_count(c, 0) == 0) {
+ if (uni_party_act_count(c, 1) == 0) {
+ if (c->cstate != CALLST_U11) {
+ make_drop_cause(c, &rej->rej.cause);
+ clear_callD(c);
+ }
+ uni_msg_destroy(api);
+ } else {
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_ADD_PARTY_REJ_indication, 0, api);
+ set_call_state(c, CALLST_N7);
+ }
+ } else {
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_ADD_PARTY_REJ_indication, 0, api);
+ }
+}
+
+/*
+ * Add-party.request from API in U4 or U10
+ *
+ * Q.2971:Call-Control-U 9-10/39 (U4)
+ * Q.2971:Call-Control-U 21/39 (U10)
+ * Q.2971:Call-Control-N 12/39 (N7)
+ * Q.2971:Call-Control-N 22/39 (N10)
+ */
+static void
+unx_add_party_request(struct call *c, struct uni_msg *msg, u_int32_t cookie)
+{
+ struct uniapi_add_party_request *add =
+ uni_msg_rptr(msg, struct uniapi_add_party_request *);
+ struct party *p;
+
+ if (IE_ISGOOD(add->add.epref)) {
+ if (add->add.epref.flag != 0) {
+ uni_msg_destroy(msg);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
+ return;
+ }
+ p = uni_find_partyx(c, add->add.epref.epref, 1);
+ if (p != NULL) {
+ uni_msg_destroy(msg);
+ uniapi_call_error(c, UNIAPI_ERROR_EPREF_INUSE, cookie);
+ return;
+ }
+ } else if (!IE_ISPRESENT(add->add.epref)) {
+ allocate_epref(c, &add->add.epref);
+ if (!IE_ISPRESENT(add->add.epref)) {
+ uni_msg_destroy(msg);
+ uniapi_call_error(c, UNIAPI_ERROR_EPREF_INUSE, cookie);
+ return;
+ }
+ } else {
+ uni_msg_destroy(msg);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
+ return;
+ }
+
+ if ((p = uni_create_partyx(c, add->add.epref.epref, 1, cookie)) == NULL) {
+ uni_msg_destroy(msg);
+ uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
+ return;
+ }
+ uni_enq_party(p, SIGP_ADD_PARTY_request, cookie, msg, NULL);
+}
+
+/*
+ * Add-party-ack.request from API in U10/N10
+ *
+ * Q.2971:Call-Control-U 21/39
+ * Q.2971:Call-Control-N 22/39
+ */
+static void
+un10_add_party_ack_request(struct call *c, struct uni_msg *msg, u_int32_t cookie)
+{
+ struct uniapi_add_party_ack_request *ack =
+ uni_msg_rptr(msg, struct uniapi_add_party_ack_request *);
+ struct party *p;
+
+ if (!IE_ISGOOD(ack->ack.epref)) {
+ uni_msg_destroy(msg);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
+ return;
+ }
+ if (ack->ack.epref.flag != 1) {
+ uni_msg_destroy(msg);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
+ return;
+ }
+ if ((p = uni_find_partyx(c, ack->ack.epref.epref, 0)) == NULL) {
+ uni_msg_destroy(msg);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
+ return;
+ }
+
+ uni_enq_party(p, SIGP_ADD_PARTY_ACK_request, cookie, msg, NULL);
+}
+
+/*
+ * Party-alerting.request from API in U7/U8/U10
+ *
+ * Q.2971:Call-Control-U 14/39 U7
+ * Q.2971:Call-Control-U 15/39 U8
+ * Q.2971:Call-Control-U 21/39 U10
+ * Q.2971:Call-Control-N 8/39 N4
+ * Q.2971:Call-Control-N 22/39 N10
+ */
+static void
+unx_party_alerting_request(struct call *c, struct uni_msg *msg, u_int32_t cookie)
+{
+ struct uniapi_party_alerting_request *alert =
+ uni_msg_rptr(msg, struct uniapi_party_alerting_request *);
+ struct party *p;
+
+ if (!IE_ISGOOD(alert->alert.epref)) {
+ uni_msg_destroy(msg);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
+ return;
+ }
+ if (alert->alert.epref.flag != 1) {
+ uni_msg_destroy(msg);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
+ return;
+ }
+ if ((p = uni_find_partyx(c, alert->alert.epref.epref, 0)) == NULL) {
+ uni_msg_destroy(msg);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
+ return;
+ }
+
+ uni_enq_party(p, SIGP_PARTY_ALERTING_request, cookie, msg, NULL);
+}
+
+/*
+ * Add-party-rej.request from API in U7/U8/U10/N4/N10
+ *
+ * Q.2971:Call-Control-U 14/39 U7
+ * Q.2971:Call-Control-U 15/39 U8
+ * Q.2971:Call-Control-U 21/39 U10
+ * Q.2971:Call-Control-N 8/39 N4
+ * Q.2971:Call-Control-N 22/39 N10
+ */
+static void
+unx_add_party_rej_request(struct call *c, struct uni_msg *msg, u_int32_t cookie)
+{
+ struct uniapi_add_party_rej_request *rej =
+ uni_msg_rptr(msg, struct uniapi_add_party_rej_request *);
+ struct party *p;
+
+ if (!IE_ISGOOD(rej->rej.epref)) {
+ uni_msg_destroy(msg);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
+ return;
+ }
+ if (rej->rej.epref.flag != 1) {
+ uni_msg_destroy(msg);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
+ return;
+ }
+ if ((p = uni_find_partyx(c, rej->rej.epref.epref, 0)) == NULL) {
+ uni_msg_destroy(msg);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
+ return;
+ }
+
+ uni_enq_party(p, SIGP_ADD_PARTY_REJ_request, cookie, msg, NULL);
+}
+
+/*
+ * Drop-party.request from API in U1-U10
+ *
+ * Q.2971:Call-Control-U 21/39 U10
+ * Q.2971:Call-Control-U 26/39 U1-U9
+ * Q.2971:Call-Control-N 22/39 N10
+ * Q.2971:Call-Control-N 27/39 N1-N9
+ */
+static void
+unx_drop_party_request(struct call *c, struct uni_msg *msg, u_int32_t cookie)
+{
+ struct uniapi_drop_party_request *drop =
+ uni_msg_rptr(msg, struct uniapi_drop_party_request *);
+ struct party *p;
+
+ if (!IE_ISGOOD(drop->drop.epref)) {
+ uni_msg_destroy(msg);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
+ return;
+ }
+ if ((p = uni_find_partyx(c, drop->drop.epref.epref, !drop->drop.epref.flag)) == NULL) {
+ uni_msg_destroy(msg);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
+ return;
+ }
+
+ uni_enq_party(p, SIGP_DROP_PARTY_request, cookie, msg, NULL);
+}
+
+/*
+ * Drop-party-ack.request from API in U1-U10
+ *
+ * Q.2971:Call-Control-U 21/39 U10
+ * Q.2971:Call-Control-U 26/39 U1-U9
+ * Q.2971:Call-Control-N 22/39 N10
+ * Q.2971:Call-Control-N 27/39 N1-N9
+ */
+static void
+unx_drop_party_ack_request(struct call *c, struct uni_msg *msg,
+ u_int32_t cookie)
+{
+ struct uniapi_drop_party_ack_request *ack =
+ uni_msg_rptr(msg, struct uniapi_drop_party_ack_request *);
+ struct party *p;
+
+ if (!IE_ISGOOD(ack->ack.epref)) {
+ uni_msg_destroy(msg);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
+ return;
+ }
+ if ((p = uni_find_partyx(c, ack->ack.epref.epref, !ack->ack.epref.flag)) == NULL) {
+ uni_msg_destroy(msg);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
+ return;
+ }
+
+ uni_enq_party(p, SIGP_DROP_PARTY_ACK_request, cookie, msg, NULL);
+}
+
+/*
+ * ADD PARTY in U7/U8/U10
+ *
+ * Q.2971:Call-Control-U 14/39 U7
+ * Q.2971:Call-Control-U 15/39 U8
+ * Q.2971:Call-Control-U 21/39 U10
+ * Q.2971:Call-Control-N 8/39 N4
+ * Q.2971:Call-Control-N 21/39 N10
+ *
+ * Body already decoded
+ */
+static void
+unx_add_party(struct call *c, struct uni_msg *m, struct uni_all *u,
+ int legal)
+{
+ struct uni_all *resp;
+ struct uni_ierr *e1;
+ struct party *p = NULL;
+ enum verify vfy;
+
+ uni_mandate_epref(c->uni, &u->u.add_party.epref);
+ MANDATE_IE(c->uni, u->u.add_party.called, UNI_IE_CALLED);
+
+ /*
+ * Do part of the verify handish: according to 9.5.7.2 we must send
+ * an ADD_PARTY_REJ if mandatory IEs are bad or missing instead of
+ * clearing the call. But we must send a STATUS, if it is the EPREF!
+ */
+ if (IE_ISGOOD(u->u.add_party.epref)) {
+ c->uni->cause.u.ie.len = 0;
+ FOREACH_ERR(e1, c->uni) {
+ if (e1->err == UNI_IERR_MIS) {
+ MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_MANDAT);
+ goto rej;
+ }
+ }
+ FOREACH_ERR(e1, c->uni) {
+ if (e1->man && e1->ie != UNI_IE_EPREF &&
+ e1->act == UNI_IEACT_DEFAULT) {
+ MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_IE_INV);
+ rej:
+ uni_vfy_collect_ies(c->uni);
+ if ((resp = UNI_ALLOC()) != NULL) {
+ MK_MSG_RESP(resp, UNI_ADD_PARTY_REJ,
+ &u->u.hdr.cref);
+ MK_IE_EPREF(resp->u.add_party_rej.epref,
+ u->u.add_party.epref.epref,
+ !u->u.add_party.epref.flag);
+ resp->u.add_party_rej.cause =
+ c->uni->cause;
+
+ unx_send_add_party_rej(c, resp);
+ }
+ goto ignore;
+ }
+ }
+ p = uni_find_partyx(c, u->u.add_party.epref.epref,
+ u->u.add_party.epref.flag);
+ }
+
+ vfy = uni_verify(c->uni, u->u.hdr.act);
+
+ switch (vfy) {
+
+ case VFY_CLR:
+ uni_vfy_collect_ies(c->uni);
+ clear_callD(c);
+ goto ignore;
+
+ case VFY_RAIM:
+ case VFY_RAI:
+ uni_respond_status_verify(c->uni, &u->u.hdr.cref,
+ map_callstate(c->cstate), &u->u.add_party.epref,
+ p ? p->state : UNI_EPSTATE_NULL);
+ /* FALLTHRU */
+ case VFY_I:
+ goto ignore;
+
+ case VFY_RAP:
+ case VFY_RAPU:
+ uni_respond_status_verify(c->uni, &u->u.hdr.cref,
+ map_callstate(c->cstate), &u->u.add_party.epref,
+ UNI_EPSTATE_ADD_RCVD);
+ case VFY_OK:
+ /* FALLTHRU */
+ break;
+ }
+ if (!legal) {
+ uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
+ &u->u.add_party.epref, -1);
+ return;
+ }
+ if (!IE_ISGOOD(u->u.add_party.epref)) {
+ /* 9.5.3.2.2 */
+ if (vfy == VFY_OK) {
+ MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_IE_INV);
+
+ uni_respond_status_verify(c->uni, &u->u.hdr.cref,
+ map_callstate(c->cstate), NULL, 0);
+ }
+ goto ignore;
+ }
+
+
+ if (p == NULL && (p = uni_create_party(c, &u->u.add_party.epref))
+ == NULL)
+ goto ignore;
+
+ uni_enq_party(p, SIGP_ADD_PARTY, 0, m, u);
+ return;
+
+ ignore:
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+}
+
+/*
+ * ADD PARTY ACKNOWLEDGE
+ *
+ * Q.2971:Call-Control-U 21/39 U10
+ * Q.2971:Call-Control-N 15/39 N8
+ * Q.2971:Call-Control-N 22/39 N10
+ */
+static void
+un10n8_add_party_ack(struct call *c, struct uni_msg *m, struct uni_all *u,
+ int legal)
+{
+ struct party *p = NULL;
+
+ if (IE_ISGOOD(u->u.add_party_ack.epref)) {
+ if (u->u.add_party_ack.epref.flag == 0) {
+ IE_SETERROR(u->u.add_party_ack.epref);
+ UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF,
+ u->u.add_party_ack.epref.h.act, UNI_IERR_BAD);
+ } else {
+ p = uni_find_partyx(c, u->u.add_party_ack.epref.epref, 1);
+ if (p == NULL) {
+ respond_drop_party_ack(c,
+ &u->u.add_party_ack.epref,
+ UNI_CAUSE_ENDP_INV);
+ goto ignore;
+ }
+ }
+ }
+ uni_mandate_epref(c->uni, &u->u.add_party_ack.epref);
+
+ switch (uni_verify(c->uni, u->u.hdr.act)) {
+
+ case VFY_CLR:
+ uni_vfy_collect_ies(c->uni);
+ clear_callD(c);
+ goto ignore;
+
+ case VFY_RAIM:
+ case VFY_RAI:
+ report:
+ uni_respond_status_verify(c->uni, &u->u.hdr.cref,
+ map_callstate(c->cstate), &u->u.add_party_ack.epref,
+ p ? p->state : UNI_EPSTATE_NULL);
+ case VFY_I:
+ goto ignore;
+
+ case VFY_RAP:
+ case VFY_RAPU:
+ uni_respond_status_verify(c->uni, &u->u.hdr.cref,
+ map_callstate(c->cstate), &u->u.add_party_ack.epref,
+ p ? UNI_EPSTATE_ACTIVE : UNI_EPSTATE_NULL);
+ if (!IE_ISGOOD(u->u.party_alerting.epref))
+ /* See below */
+ goto ignore;
+ break;
+ case VFY_OK:
+ if (!IE_ISGOOD(u->u.party_alerting.epref))
+ /* this happens when the EPREF has bad format.
+ * The rules require us the message to be ignored
+ * (9.5.3.2.2e) and to report status.
+ */
+ goto report;
+ break;
+ }
+ if (legal) {
+ /* p is != NULL here */
+ uni_enq_party(p, SIGP_ADD_PARTY_ACK, 0, m, u);
+ return;
+ }
+ if (p == NULL)
+ /* Q.2971 9.5.3.2.3a) */
+ respond_drop_party_ack(c, &u->u.add_party_ack.epref,
+ UNI_CAUSE_ENDP_INV);
+ else
+ uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
+ &u->u.add_party_ack.epref, p->state);
+
+ ignore:
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+}
+
+/*
+ * Make the EPREF action default
+ */
+static void
+default_act_epref(struct uni *uni, struct uni_ie_epref *epref)
+{
+ struct uni_ierr *e;
+
+ FOREACH_ERR(e, uni)
+ if (e->ie == UNI_IE_EPREF) {
+ e->act = UNI_IEACT_DEFAULT;
+ break;
+ }
+ epref->h.act = UNI_IEACT_DEFAULT;
+}
+
+/*
+ * PARTY ALERTING message
+ *
+ * Q.2971:Call-Control-U 9/39 U4
+ * Q.2971:Call-Control-U 21/39 U10
+ * Q.2971:Call-Control-N 12/39 N7
+ * Q.2971:Call-Control-N 15/39 N8
+ * Q.2971:Call-Control-N 22/39 N10
+ */
+static void
+unx_party_alerting(struct call *c, struct uni_msg *m, struct uni_all *u,
+ int legal)
+{
+ struct party *p = NULL;
+
+ if (IE_ISGOOD(u->u.party_alerting.epref)) {
+ if (u->u.party_alerting.epref.flag == 0) {
+ IE_SETERROR(u->u.party_alerting.epref);
+ UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF,
+ u->u.party_alerting.epref.h.act, UNI_IERR_BAD);
+ } else {
+ p = uni_find_partyx(c, u->u.party_alerting.epref.epref, 1);
+ if (p == NULL) {
+ respond_drop_party_ack(c,
+ &u->u.party_alerting.epref,
+ UNI_CAUSE_ENDP_INV);
+ goto ignore;
+ }
+ }
+ }
+ uni_mandate_epref(c->uni, &u->u.party_alerting.epref);
+
+ switch (uni_verify(c->uni, u->u.hdr.act)) {
+
+ case VFY_CLR:
+ uni_vfy_collect_ies(c->uni);
+ clear_callD(c);
+ goto ignore;
+
+ case VFY_RAIM:
+ case VFY_RAI:
+ report:
+ uni_respond_status_verify(c->uni, &u->u.hdr.cref,
+ map_callstate(c->cstate), &u->u.party_alerting.epref,
+ p ? p->state : UNI_EPSTATE_NULL);
+ case VFY_I:
+ goto ignore;
+
+ case VFY_RAP:
+ case VFY_RAPU:
+ uni_respond_status_verify(c->uni, &u->u.hdr.cref,
+ map_callstate(c->cstate), &u->u.party_alerting.epref,
+ p ? UNI_EPSTATE_ALERT_RCVD : UNI_EPSTATE_NULL);
+ if (!IE_ISGOOD(u->u.party_alerting.epref))
+ /* See below */
+ goto ignore;
+ break;
+
+ case VFY_OK:
+ if (!IE_ISGOOD(u->u.party_alerting.epref))
+ /* The rules require us the message to be ignored
+ * (9.5.3.2.2e) and to report status.
+ */
+ goto report;
+ break;
+ }
+ if (legal) {
+ /* p is != NULL here */
+ uni_enq_party(p, SIGP_PARTY_ALERTING, 0, m, u);
+ return;
+ }
+ if (p == NULL)
+ /* Q.2971 9.5.3.2.3a) */
+ respond_drop_party_ack(c, &u->u.party_alerting.epref,
+ UNI_CAUSE_ENDP_INV);
+ else
+ uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
+ &u->u.party_alerting.epref, p->state);
+
+ ignore:
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+}
+
+/*
+ * Handle a bad/missing cause in a DROP_PARTY_ACK or ADD_PARTY_REJ
+ *
+ * If the IE is missing or bad and the action is defaulted handle as
+ * cause #1 according to 9.5.7.1/2.
+ * Otherwise keep the IE.
+ */
+static void
+handle_bad_drop_cause(struct call *c, struct uni_ie_cause *cause, int mkcause)
+{
+
+ if (IE_ISGOOD(*cause))
+ return;
+
+ if (!IE_ISPRESENT(*cause)) {
+ /* 9.5.7.1 */
+ /* cannot make cause here because we need the 96 error */
+ uni_vfy_remove_cause(c->uni);
+ return;
+ }
+ if (cause->h.act != UNI_IEACT_DEFAULT)
+ return;
+
+ /* 9.5.7.2 */
+ uni_vfy_remove_cause(c->uni);
+ if (mkcause)
+ MK_IE_CAUSE(*cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_UNSPEC);
+}
+
+/*
+ * ADD PARTY REJ from party control
+ * Q.2971:Call-Control-U 21/39
+ * Q.2971:Call-Control-U 24/39
+ */
+static void
+unx_send_add_party_rej(struct call *c, struct uni_all *u)
+{
+
+ if (uni_party_act_count(c, 2) == 0) {
+ if (c->cstate != CALLST_U11 && c->cstate != CALLST_N12) {
+ c->uni->cause = u->u.add_party_rej.cause;
+ clear_callD(c);
+ }
+ } else
+ (void)uni_send_output(u, c->uni);
+ UNI_FREE(u);
+}
+
+/*
+ * ADD_PARTY_REJECT in U4/U10
+ *
+ * Q.2971:Call-Control-U 9/39 U4
+ * Q.2971:Call-Control-U 21/39 U10
+ * Q.2971:Call-Control-N 12/39 N7
+ * Q.2971:Call-Control-N 15/39 N8
+ * Q.2971:Call-Control-N 22/39 N10
+ */
+static void
+unx_add_party_rej(struct call *c, struct uni_msg *m, struct uni_all *u,
+ int legal)
+{
+ struct uni_add_party_rej *ar = &u->u.add_party_rej;
+ struct party *p;
+
+ if (IE_ISGOOD(ar->epref)) {
+ p = uni_find_partyx(c, ar->epref.epref, ar->epref.flag);
+ if (p == NULL)
+ goto ignore;
+
+ if (legal) {
+ handle_bad_drop_cause(c, &ar->cause, 0);
+ uni_vfy_remove_unknown(c->uni);
+ switch (uni_verify(c->uni, u->u.hdr.act)) {
+
+ case VFY_CLR:
+ goto clear;
+
+ case VFY_RAIM:
+ case VFY_RAI:
+ uni_respond_status_verify(c->uni,
+ &u->u.hdr.cref, map_callstate(c->cstate),
+ &ar->epref, p->state);
+ case VFY_I:
+ goto ignore;
+
+ case VFY_RAPU:
+ uni_vfy_collect_ies(c->uni);
+ break;
+
+ case VFY_RAP:
+ uni_respond_status_verify(c->uni,
+ &u->u.hdr.cref, map_callstate(c->cstate),
+ &ar->epref, p->state);
+ case VFY_OK:
+ break;
+ }
+ uni_enq_party(p, SIGP_ADD_PARTY_REJ, 0, m, u);
+ return;
+ }
+ uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
+ &ar->epref, -1);
+ return;
+ }
+
+ /* Q.2971: 9.5.3.2.1 last paragraph
+ * 9.5.3.2.2 second to last paragraph
+ * Make the action indicator default.
+ */
+ default_act_epref(c->uni, &ar->epref);
+ if (!IE_ISPRESENT(ar->epref))
+ uni_mandate_ie(c->uni, UNI_IE_EPREF);
+ (void)uni_verify(c->uni, u->u.hdr.act);
+
+ clear:
+ uni_vfy_collect_ies(c->uni);
+ clear_callD(c);
+
+ ignore:
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+}
+
+/*
+ * DROP_PARTY
+ *
+ * Q.2971:Call-Control-U 26/39 Ux
+ * Q.2971:Call-Control-U 21/39 U10
+ * Q.2971:Call-Control-N 27/39 Nx
+ * Q.2971:Call-Control-N 22/39 N10
+ */
+static void
+unx_drop_party(struct call *c, struct uni_msg *m, struct uni_all *u, int legal)
+{
+ struct uni_drop_party *dp = &u->u.drop_party;
+ struct party *p;
+ struct uni_ierr *e;
+
+ if (IE_ISGOOD(dp->epref)) {
+ p = uni_find_partyx(c, dp->epref.epref, dp->epref.flag);
+ if (p == NULL) {
+ respond_drop_party_ack(c, &dp->epref,
+ UNI_CAUSE_ENDP_INV);
+ goto ignore;
+ }
+ handle_bad_drop_cause(c, &dp->cause, 0);
+ uni_vfy_remove_unknown(c->uni);
+ switch (uni_verify(c->uni, u->u.hdr.act)) {
+
+ case VFY_CLR:
+ goto clear;
+
+ case VFY_RAIM:
+ case VFY_RAI:
+ uni_respond_status_verify(c->uni, &u->u.hdr.cref,
+ map_callstate(c->cstate),
+ &u->u.drop_party.epref, p->state);
+ case VFY_I:
+ goto ignore;
+
+ case VFY_RAPU:
+ uni_vfy_collect_ies(c->uni);
+ break;
+
+ case VFY_RAP:
+ uni_respond_status_verify(c->uni, &u->u.hdr.cref,
+ map_callstate(c->cstate),
+ &dp->epref, UNI_EPSTATE_DROP_RCVD);
+ case VFY_OK:
+ break;
+ }
+ if (legal) {
+ uni_enq_party(p, SIGP_DROP_PARTY, 0, m, u);
+ return;
+ }
+ uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, &dp->epref, -1);
+ goto ignore;
+ }
+
+ /* Q.2971: 9.5.3.2.1 last paragraph
+ * 9.5.3.2.2 second to last paragraph
+ * Make the action indicator default.
+ */
+ FOREACH_ERR(e, c->uni)
+ if (e->ie == UNI_IE_EPREF) {
+ e->act = UNI_IEACT_DEFAULT;
+ break;
+ }
+ dp->epref.h.act = UNI_IEACT_DEFAULT;
+
+ if (!IE_ISPRESENT(dp->epref))
+ uni_mandate_ie(c->uni, UNI_IE_EPREF);
+ (void)uni_verify(c->uni, u->u.hdr.act);
+
+ clear:
+ uni_vfy_collect_ies(c->uni);
+ clear_callD(c);
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+ return;
+
+ ignore:
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+}
+
+/*
+ * DROP_PARTY_ACK
+ *
+ * Q.2971:Call-Control-U 26/39 Ux
+ * Q.2971:Call-Control-U 21/39 U10
+ * Q.2971:Call-Control-N 27/39 Nx
+ * Q.2971:Call-Control-N 22/39 N10
+ */
+static void
+unx_drop_party_ack(struct call *c, struct uni_msg *m, struct uni_all *u,
+ int legal)
+{
+ struct party *p;
+ struct uni_drop_party_ack *ack = &u->u.drop_party_ack;
+
+ if (IE_ISGOOD(u->u.drop_party_ack.epref)) {
+ p = uni_find_partyx(c, ack->epref.epref, ack->epref.flag);
+ if (p != NULL) {
+ handle_bad_drop_cause(c, &ack->cause, 1);
+ uni_vfy_remove_unknown(c->uni);
+ switch (uni_verify(c->uni, u->u.hdr.act)) {
+
+ case VFY_CLR:
+ goto clear;
+
+ case VFY_RAIM:
+ case VFY_RAI:
+ uni_respond_status_verify(c->uni,
+ &u->u.hdr.cref, map_callstate(c->cstate),
+ &ack->epref, p->state);
+ case VFY_I:
+ goto ignore;
+
+ case VFY_RAP:
+ uni_respond_status_verify(c->uni,
+ &u->u.hdr.cref, map_callstate(c->cstate),
+ &ack->epref, UNI_EPSTATE_NULL);
+ case VFY_RAPU:
+ case VFY_OK:
+ break;
+ }
+ if (legal) {
+ uni_enq_party(p, SIGP_DROP_PARTY_ACK, 0, m, u);
+ return;
+ }
+ uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
+ &ack->epref, -1);
+ }
+ goto ignore;
+ }
+
+ /* Q.2971: 9.5.3.2.1 last paragraph
+ * 9.5.3.2.2 second to last paragraph
+ */
+ (void)uni_verify(c->uni, u->u.hdr.act);
+ MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_IE_INV);
+
+ clear:
+ uni_vfy_collect_ies(c->uni);
+ clear_callD(c);
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+ return;
+
+ ignore:
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+}
+
+/**********************************************************************/
+
+/*
+ * Bad or unrecognized message.
+ *
+ * Q.2971:Call-Control-U 35/39
+ */
+void
+uni_bad_message(struct call *c, struct uni_all *u, u_int cause,
+ struct uni_ie_epref *epref, int ps)
+{
+ struct uni_all *resp;
+ struct party *p;
+
+ if ((u->u.hdr.act == UNI_MSGACT_CLEAR &&
+ (c->cstate == CALLST_U11 ||
+ c->cstate == CALLST_U12 ||
+ c->cstate == CALLST_N11 ||
+ c->cstate == CALLST_N12)) ||
+ u->u.hdr.act == UNI_MSGACT_IGNORE)
+ return;
+
+ MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, cause);
+ ADD_CAUSE_MTYPE(c->uni->cause, u->mtype);
+
+ if (u->u.hdr.act == UNI_MSGACT_CLEAR) {
+ clear_callD(c);
+ return;
+ }
+
+ /*
+ * Send STATUS
+ */
+ if ((resp = UNI_ALLOC()) != NULL) {
+ MK_MSG_RESP(resp, UNI_STATUS, &u->u.hdr.cref);
+ MK_IE_CALLSTATE(resp->u.status.callstate,
+ map_callstate(c->cstate));
+ resp->u.status.cause = c->uni->cause;
+
+ if (epref != NULL && IE_ISGOOD(*epref)) {
+ MK_IE_EPREF(resp->u.status.epref, epref->epref, !epref->flag);
+ if (ps == -1) {
+ p = uni_find_party(c, epref);
+ if (p == NULL)
+ ps = UNI_EPSTATE_NULL;
+ else
+ ps = p->state;
+ }
+ MK_IE_EPSTATE(resp->u.status.epstate, ps);
+ }
+ (void)uni_send_output(resp, c->uni);
+
+ UNI_FREE(resp);
+ }
+}
+
+/**********************************************************************/
+
+/*
+ * Unknown message in any state.
+ *
+ * Q.2971:Call-Control 35/39
+ * Q.2971:Call-Control 36/39
+ */
+static void
+unx_unknown(struct call *c, struct uni_msg *m, struct uni_all *u)
+{
+ /*
+ * Unrecognized message. Cannot call verify here, because
+ * it doesn't know about unrecognized messages.
+ */
+ if (u->u.hdr.act == UNI_MSGACT_CLEAR) {
+ MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_MTYPE_NIMPL);
+ ADD_CAUSE_MTYPE(c->uni->cause, u->mtype);
+ clear_callD(c);
+ } else if(u->u.hdr.act == UNI_MSGACT_IGNORE) {
+ ;
+ } else {
+ (void)uni_decode_body(m, u, &c->uni->cx);
+ uni_bad_message(c, u, UNI_CAUSE_MTYPE_NIMPL,
+ &u->u.unknown.epref, -1);
+ }
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+}
+/**********************************************************************/
+
+void
+uni_sig_call(struct call *c, enum call_sig sig, u_int32_t cookie,
+ struct uni_msg *msg, struct uni_all *u)
+{
+ if (sig >= SIGC_END) {
+ VERBOSE(c->uni, UNI_FAC_ERR, 1,
+ "Signal %d outside of range to Call-Control", sig);
+ if (msg)
+ uni_msg_destroy(msg);
+ if (u)
+ UNI_FREE(u);
+ return;
+ }
+
+ VERBOSE(c->uni, UNI_FAC_CALL, 1, "Signal %s in state %s of call %u/%s"
+ "; cookie %u", call_sigs[sig], callstates[c->cstate].name, c->cref,
+ c->mine ? "mine" : "his", cookie);
+
+ switch (sig) {
+
+ case SIGC_LINK_RELEASE_indication:
+ if (c->cstate == CALLST_U10 || c->cstate == CALLST_N10)
+ /* Q.2971:Call-Control-U 36/39 */
+ /* Q.2971:Call-Control-N 20/39 */
+ un10_link_release_indication(c);
+ else
+ /* Q.2971:Call-Control-U 36/39 */
+ /* Q.2971:Call-Control-N 37/39 */
+ unx_link_release_indication(c);
+ break;
+
+ case SIGC_LINK_ESTABLISH_ERROR_indication:
+ if (c->cstate != CALLST_U10 && c->cstate != CALLST_N10) {
+ VERBOSE(c->uni, UNI_FAC_ERR, 1,
+ "link-establish-error.indication in cs=%s",
+ callstates[c->cstate].name);
+ break;
+ }
+ /* Q.2971:Call-Control-U 19/39 */
+ /* Q.2971:Call-Control-N 20/39 */
+ un10_link_establish_error_indication(c);
+ break;
+
+ case SIGC_LINK_ESTABLISH_indication:
+ switch (c->cstate) {
+
+ case CALLST_U1: case CALLST_N1:
+ case CALLST_U3: case CALLST_N3:
+ case CALLST_U4: case CALLST_N4:
+ case CALLST_U6: case CALLST_N6:
+ case CALLST_U7: case CALLST_N7:
+ case CALLST_U8: case CALLST_N8:
+ case CALLST_U9: case CALLST_N9:
+ /* Q.2971:Call-Control-U 36/39 */
+ /* Q.2971:Call-Control-N 37/39 */
+ unx_link_establish_indication(c);
+ break;
+
+ case CALLST_U10: case CALLST_N10:
+ /* Q.2971:Call-Control-U 19/39 */
+ /* Q.2971:Call-Control-N 20/39 */
+ un10_link_establish_indication(c);
+ break;
+
+ case CALLST_U11: case CALLST_N11:
+ case CALLST_U12: case CALLST_N12:
+ /* Q.2971:Call-Control-U 36/39 */
+ /* Q.2971:Call-Control-N 37/39 */
+ break;
+
+ default:
+ VERBOSE(c->uni, UNI_FAC_ERR, 1,
+ "link-establish.indication in cs=%s",
+ callstates[c->cstate].name);
+ }
+ break;
+
+ case SIGC_LINK_ESTABLISH_confirm:
+ if (c->cstate != CALLST_U10 && c->cstate != CALLST_N10) {
+ VERBOSE(c->uni, UNI_FAC_ERR, 1,
+ "link-establish.confirm in cs=%s",
+ callstates[c->cstate].name);
+ break;
+ }
+ /* Q.2971:Call-Control-U 19/39 */
+ /* Q.2971:Call-Control-N 20/39 */
+ un10_link_establish_confirm(c);
+ break;
+
+ case SIGC_UNKNOWN:
+ /* Q.2971:Call-Control 35/39 */
+ /* Q.2971:Call-Control 36/39 */
+ unx_unknown(c, msg, u);
+ break;
+
+ case SIGC_SETUP:
+ if (c->cstate != CALLST_NULL) {
+ (void)uni_decode_body(msg, u, &c->uni->cx);
+ uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
+ &u->u.setup.epref, -1);
+ goto drop;
+ }
+ if (c->uni->proto == UNIPROTO_UNI40N)
+ /* Q.2971:Call-Control-N 4/39 */
+ un0_setup(c, msg, u, CALLST_N1);
+ else
+ /* Q.2971:Call-Control-U 4/39 */
+ un0_setup(c, msg, u, CALLST_U6);
+ break;
+
+ case SIGC_CALL_PROC:
+ if (c->cstate == CALLST_U1) {
+ /* Q.2971:Call-Control-U 6/39 */
+ u1n6_call_proc(c, msg, u, CALLST_U3);
+ break;
+ }
+ if (c->cstate == CALLST_N6) {
+ /* Q.2971:Call-Control-N 11/39 */
+ u1n6_call_proc(c, msg, u, CALLST_N9);
+ break;
+ }
+ (void)uni_decode_body(msg, u, &c->uni->cx);
+ uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
+ &u->u.call_proc.epref, -1);
+ goto drop;
+
+ case SIGC_ALERTING:
+ if (c->cstate == CALLST_U1 || c->cstate == CALLST_U3) {
+ /* Q.2971:Call-Control-U 37/39 (U1) */
+ /* Q.2971:Call-Control-U 7/39 (U3) */
+ unx_alerting(c, msg, u, CALLST_U4);
+ break;
+ }
+ if (c->cstate == CALLST_N6) {
+ /* Q.2971:Call-Control-N 9/39 (N6) */
+ /* Q.2971:Call-Control-N 17/39 (N9) */
+ unx_alerting(c, msg, u, CALLST_N7);
+ break;
+ }
+ (void)uni_decode_body(msg, u, &c->uni->cx);
+ uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
+ &u->u.alerting.epref, -1);
+ goto drop;
+
+ case SIGC_CONNECT:
+ if (c->cstate == CALLST_U1 || c->cstate == CALLST_U3 ||
+ c->cstate == CALLST_U4) {
+ /* Q.2971:Call-Control-U 7-8/39 (U3) */
+ /* Q.2971:Call-Control-U 11/39 (U4) */
+ /* Q.2971:Call-Control-U 37/39 (U1) */
+ unx_connect(c, msg, u, CALLST_U10);
+ break;
+ }
+ if (c->cstate == CALLST_N6 || c->cstate == CALLST_N7 ||
+ c->cstate == CALLST_N9) {
+ /* Q.2971:Call-Control-N 9-10/39 (N6) */
+ /* Q.2971:Call-Control-N 14/39 (N7) */
+ /* Q.2971:Call-Control-N 17/39 (N9) */
+ unx_connect(c, msg, u, CALLST_N8);
+ break;
+ }
+ (void)uni_decode_body(msg, u, &c->uni->cx);
+ uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
+ &u->u.connect.epref, -1);
+ goto drop;
+
+ case SIGC_CONNECT_ACK:
+ if (c->cstate == CALLST_U8) {
+ /* Q.2971:Call-Control-U 15-16/39 */
+ u8_connect_ack(c, msg, u, CALLST_U10);
+ break;
+ }
+ if (c->cstate == CALLST_N10) {
+ /* Q.2971:Call-Control-N 18/39 */
+ n10_connect_ack(c, msg, u);
+ break;
+ }
+ uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, NULL, 0);
+ goto drop;
+
+ case SIGC_RELEASE:
+ switch (c->cstate) {
+
+ default:
+ uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, NULL, 0);
+ goto drop;
+
+ case CALLST_U11:
+ case CALLST_N12:
+ /* Q.2971:Call-Control-U 28/39 */
+ /* Q.2971:Call-Control-N 30/39 */
+ u11n12_release(c, msg, u);
+ break;
+
+ case CALLST_U1:
+ case CALLST_U3:
+ case CALLST_U4:
+ case CALLST_U6:
+ case CALLST_U7:
+ case CALLST_U8:
+ case CALLST_U9:
+ case CALLST_U10:
+ case CALLST_U12:
+ /* Q.2971:Call-Control-U 25/39 */
+ unx_release(c, msg, u, CALLST_U12);
+ break;
+
+ case CALLST_N1:
+ case CALLST_N3:
+ case CALLST_N4:
+ case CALLST_N6:
+ case CALLST_N7:
+ case CALLST_N8:
+ case CALLST_N9:
+ case CALLST_N10:
+ case CALLST_N11:
+ /* Q.2971:Call-Control-N 26/39 */
+ unx_release(c, msg, u, CALLST_N11);
+ break;
+ }
+ break;
+
+ case SIGC_RELEASE_COMPL:
+ /* Q.2971:Call-Control-U 25/39 */
+ /* Q.2971:Call-Control-N 26/39 */
+ unx_release_compl(c, msg, u);
+ break;
+
+ case SIGC_NOTIFY:
+ /* Q.2971:Call-Control-U 18/39 */
+ /* Q.2971:Call-Control-N 19/39 */
+ unx_notify(c, msg, u);
+ break;
+
+ case SIGC_STATUS:
+ if (c->cstate == CALLST_U11 || c->cstate == CALLST_U12 ||
+ c->cstate == CALLST_N11 || c->cstate == CALLST_N12) {
+ /* Q.2971:Call-Control-U 29/39 (U11) */
+ /* Q.2971:Call-Control-U 30/39 (U12) */
+ /* Q.2971:Call-Control-N 29/39 (N11) */
+ /* Q.2971:Call-Control-N 31/39 (N12) */
+ un11un12_status(c, msg, u);
+ break;
+ }
+ /* Q.2971:Call-Control-U 32/39 */
+ /* Q.2971:Call-Control-N 33/39 */
+ unx_status(c, msg, u);
+ break;
+
+ case SIGC_STATUS_ENQ:
+ /* Q.2971:Call-Control-U 31/39 */
+ /* Q.2971:Call-Control-N 32/39 */
+ unx_status_enq(c, msg, u);
+ break;
+
+ case SIGC_ADD_PARTY:
+ (void)uni_decode_body(msg, u, &c->uni->cx);
+
+ if (c->type != CALL_LEAF && c->type != CALL_ROOT) {
+ uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
+ &u->u.add_party.epref, UNI_EPSTATE_NULL);
+ goto drop;
+ }
+ switch (c->cstate) {
+ case CALLST_U7:
+ case CALLST_U8:
+ case CALLST_U10:
+ case CALLST_N4:
+ case CALLST_N10:
+ /* Q.2971:Call-Control-U 14/39 U7 */
+ /* Q.2971:Call-Control-U 15/39 U8 */
+ /* Q.2971:Call-Control-U 21/39 U10 */
+ /* Q.2971:Call-Control-N 8/39 N4 */
+ /* Q.2971:Call-Control-N 21/39 N10 */
+ unx_add_party(c, msg, u, 1);
+ break;
+
+ default:
+ unx_add_party(c, msg, u, 0);
+ goto drop;
+ }
+ break;
+
+ case SIGC_PARTY_ALERTING:
+ (void)uni_decode_body(msg, u, &c->uni->cx);
+
+ if (c->type != CALL_ROOT) {
+ uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
+ &u->u.party_alerting.epref, -1);
+ goto drop;
+ }
+ switch (c->cstate) {
+
+ default:
+ /* Q.2971 9.5.3.2.3a) */
+ unx_party_alerting(c, msg, u, 0);
+ break;
+
+ case CALLST_U4:
+ case CALLST_U10:
+ /* Q.2971:Call-Control-U 9/39 U4 */
+ /* Q.2971:Call-Control-U 21/39 U10 */
+ /* Q.2971:Call-Control-N 12/39 N7 */
+ /* Q.2971:Call-Control-N 15/39 N8 */
+ /* Q.2971:Call-Control-N 22/39 N10 */
+ unx_party_alerting(c, msg, u, 1);
+ break;
+ }
+ break;
+
+ case SIGC_ADD_PARTY_ACK:
+ (void)uni_decode_body(msg, u, &c->uni->cx);
+
+ if (c->type != CALL_ROOT) {
+ uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
+ &u->u.add_party_rej.epref, -1);
+ goto drop;
+ }
+ switch (c->cstate) {
+
+ case CALLST_U10:
+ /* Q.2971:Call-Control-U 21/39 U10 */
+ /* Q.2971:Call-Control-N 15/39 N8 */
+ /* Q.2971:Call-Control-N 22/39 N10 */
+ un10n8_add_party_ack(c, msg, u, 1);
+ break;
+
+ default:
+ /* Q.2971 9.5.3.2.3a) */
+ un10n8_add_party_ack(c, msg, u, 0);
+ break;
+ }
+ break;
+
+ case SIGC_ADD_PARTY_REJ:
+ (void)uni_decode_body(msg, u, &c->uni->cx);
+
+ if (c->type != CALL_ROOT) {
+ uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
+ &u->u.add_party_rej.epref, -1);
+ goto drop;
+ }
+ switch (c->cstate) {
+
+ case CALLST_U4:
+ case CALLST_U10:
+ case CALLST_N7:
+ case CALLST_N8:
+ case CALLST_N10:
+ /* Q.2971:Call-Control-U 9/39 U4 */
+ /* Q.2971:Call-Control-U 21/39 U10 */
+ /* Q.2971:Call-Control-N 12/39 N7 */
+ /* Q.2971:Call-Control-N 15/39 N8 */
+ /* Q.2971:Call-Control-N 22/39 N10 */
+ unx_add_party_rej(c, msg, u, 1);
+ break;
+
+ default:
+ /* Q.2971: 9.5.3.2.3b */
+ unx_add_party_rej(c, msg, u, 0);
+ break;
+ }
+ break;
+
+ case SIGC_DROP_PARTY:
+ (void)uni_decode_body(msg, u, &c->uni->cx);
+
+ if (c->type != CALL_ROOT && c->type != CALL_LEAF) {
+ uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
+ &u->u.drop_party.epref, -1);
+ goto drop;
+ }
+ switch (c->cstate) {
+ case CALLST_U11:
+ case CALLST_U12:
+ case CALLST_N11:
+ case CALLST_N12:
+ /* Q.2971:Call-Control-U 28/39 U11 */
+ /* Q.2971:Call-Control-U 30/39 U12 */
+ /* Q.2971:Call-Control-N 29/39 N11 */
+ /* Q.2971:Call-Control-N 30/39 N12 */
+ goto drop;
+
+ case CALLST_NULL:
+ uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
+ &u->u.drop_party.epref, UNI_EPSTATE_NULL);
+ goto drop;
+
+ case CALLST_U3:
+ case CALLST_N3:
+ /* L3MU_17_38 */
+ unx_drop_party(c, msg, u, 0);
+ break;
+
+ case CALLST_U8:
+ if (c->uni->sb_tb) {
+ /* L3MU_06_0[3-6] */
+ unx_drop_party(c, msg, u, 0);
+ break;
+ }
+ /* FALLTHRU */
+
+ default:
+ /* Q.2971:Call-Control-U 26/39 Ux */
+ /* Q.2971:Call-Control-U 21/39 U10 */
+ /* Q.2971:Call-Control-N 27/39 Nx */
+ /* Q.2971:Call-Control-N 21/39 N10 */
+ unx_drop_party(c, msg, u, 1);
+ break;
+ }
+ break;
+
+ case SIGC_DROP_PARTY_ACK:
+ (void)uni_decode_body(msg, u, &c->uni->cx);
+
+ if (c->type != CALL_ROOT && c->type != CALL_LEAF) {
+ uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
+ &u->u.drop_party_ack.epref, -1);
+ goto drop;
+ }
+ switch (c->cstate) {
+
+ case CALLST_U11:
+ case CALLST_U12:
+ /* Q.2971:Call-Control-U 28/39 U11 */
+ /* Q.2971:Call-Control-U 30/39 U12 */
+ /* Q.2971:Call-Control-N 29/39 N11 */
+ /* Q.2971:Call-Control-N 30/39 N12 */
+ goto drop;
+
+ case CALLST_NULL:
+ uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
+ &u->u.drop_party.epref, UNI_EPSTATE_NULL);
+ goto drop;
+
+ case CALLST_U4:
+ case CALLST_N4:
+ case CALLST_U7:
+ case CALLST_N7:
+ case CALLST_U8:
+ case CALLST_N8:
+ case CALLST_U10:
+ case CALLST_N10:
+ /* Q.2971:Call-Control-U 26/39 Ux */
+ /* Q.2971:Call-Control-U 21/39 U10 */
+ /* Q.2971:Call-Control-N 27/39 Nx */
+ /* Q.2971:Call-Control-N 22/39 N10 */
+ unx_drop_party_ack(c, msg, u, 1);
+ break;
+
+ default:
+ /* Q.2971 10.5 4th paragraph */
+ unx_drop_party_ack(c, msg, u, 0);
+ break;
+ }
+ break;
+
+ case SIGC_COBISETUP: /* XXX */
+ unx_unknown(c, msg, u);
+ break;
+
+ /*
+ * User signals
+ */
+ case SIGC_SETUP_request:
+ if (c->cstate == CALLST_NULL) {
+ /* Q.2971:Call-Control-U 4/39 (U0) */
+ /* Q.2971:Call-Control-N 4/39 (N0) */
+ if (c->uni->proto == UNIPROTO_UNI40N)
+ un0_setup_request(c, msg, cookie, CALLST_N6);
+ else
+ un0_setup_request(c, msg, cookie, CALLST_U1);
+ break;
+ }
+ VERBOSE(c->uni, UNI_FAC_ERR, 1, "setup.request in cs=%s",
+ callstates[c->cstate].name);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
+ uni_msg_destroy(msg);
+ break;
+
+ case SIGC_SETUP_response:
+ if (c->cstate == CALLST_U6 || c->cstate == CALLST_U9 ||
+ c->cstate == CALLST_U7) {
+ /* Q.2971:Call-Control-U 13/39 (U6) */
+ /* Q.2971:Call-Control-U 14/39 (U7) */
+ /* Q.2971:Call-Control-U 17/39 (U9) */
+ unx_setup_response(c, msg, cookie, CALLST_U8);
+ break;
+ }
+ if (c->cstate == CALLST_N1 || c->cstate == CALLST_N3 ||
+ c->cstate == CALLST_N4) {
+ /* Q.2971:Call-Control-N 39/39 (N1) */
+ /* Q.2971:Call-Control-N 7/39 (N3) */
+ /* Q.2971:Call-Control-N 8/39 (N4) */
+ unx_setup_response(c, msg, cookie, CALLST_N10);
+ break;
+ }
+ VERBOSE(c->uni, UNI_FAC_ERR, 1, "setup.response in cs=%s",
+ callstates[c->cstate].name);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
+ uni_msg_destroy(msg);
+ break;
+
+ case SIGC_SETUP_COMPLETE_request:
+ if (c->cstate == CALLST_N8) {
+ /* Q.2971:Call-Control-N 15/39 (N8) */
+ n8_setup_compl_request(c, msg, cookie, CALLST_N10);
+ break;
+ }
+ VERBOSE(c->uni, UNI_FAC_ERR, 1, "setup_compl.request in cs=%s",
+ callstates[c->cstate].name);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
+ uni_msg_destroy(msg);
+ break;
+
+ case SIGC_PROCEEDING_request:
+ if (c->cstate == CALLST_U6) {
+ /* Q.2971:Call-Control-U 12/39 (U6) */
+ u6n1_proceeding_request(c, msg, cookie, CALLST_U9);
+ break;
+ }
+ if (c->cstate == CALLST_N1) {
+ /* Q.2971:Call-Control-N 6/39 (N1) */
+ u6n1_proceeding_request(c, msg, cookie, CALLST_N3);
+ break;
+ }
+ VERBOSE(c->uni, UNI_FAC_ERR, 1, "proceeding.request in cs=%s",
+ callstates[c->cstate].name);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
+ uni_msg_destroy(msg);
+ break;
+
+ case SIGC_ALERTING_request:
+ if (c->cstate == CALLST_U6 || c->cstate == CALLST_U9) {
+ /* Q.2971:Call-Control-U 13/39 (U6) */
+ /* Q.2971:Call-Control-U 17/39 (U9) */
+ unx_alerting_request(c, msg, cookie, CALLST_U7);
+ break;
+ }
+ if (c->cstate == CALLST_N1 || c->cstate == CALLST_N1) {
+ /* Q.2971:Call-Control-N 38/39 (N1) */
+ /* Q.2971:Call-Control-N 7/39 (N3) */
+ unx_alerting_request(c, msg, cookie, CALLST_N4);
+ break;
+ }
+ VERBOSE(c->uni, UNI_FAC_ERR, 1, "alerting.request in cs=%s",
+ callstates[c->cstate].name);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
+ uni_msg_destroy(msg);
+ break;
+
+ case SIGC_RELEASE_request:
+ switch (c->cstate) {
+
+ case CALLST_U1:
+ case CALLST_U3:
+ case CALLST_U4:
+ case CALLST_U6:
+ case CALLST_U7:
+ case CALLST_U8:
+ case CALLST_U9:
+ case CALLST_U10:
+ /* Q.2971:Call-Control-U 27/39 */
+ unx_release_request(c, msg, cookie, CALLST_U11);
+ break;
+
+ case CALLST_N1:
+ case CALLST_N3:
+ case CALLST_N4:
+ case CALLST_N6:
+ case CALLST_N7:
+ case CALLST_N8:
+ case CALLST_N9:
+ case CALLST_N10:
+ /* Q.2971:Call-Control-N 28/39 */
+ unx_release_request(c, msg, cookie, CALLST_N12);
+ break;
+
+ case CALLST_U11:
+ case CALLST_U12:
+ case CALLST_N11:
+ case CALLST_N12:
+ case CALLST_NULL:
+ VERBOSE(c->uni, UNI_FAC_ERR, 1,
+ "release.request in cs=%s",
+ callstates[c->cstate].name);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE,
+ cookie);
+ uni_msg_destroy(msg);
+ break;
+ }
+ break;
+
+ case SIGC_RELEASE_response:
+ if (c->cstate == CALLST_U6 || c->cstate == CALLST_U12 ||
+ c->cstate == CALLST_N1 || c->cstate == CALLST_N11) {
+ /* Q.2971:Call-Control-U 12/39 (U6) */
+ /* Q.2971:Call-Control-U 30/39 (U12) */
+ /* Q.2971:Call-Control-N 6/39 (N1) */
+ /* Q.2971:Call-Control-N 29/39 (N11) */
+ unx_release_response(c, msg, cookie);
+ break;
+ }
+ VERBOSE(c->uni, UNI_FAC_ERR, 1, "release.response in cs=%s",
+ callstates[c->cstate].name);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
+ uni_msg_destroy(msg);
+ break;
+
+ case SIGC_NOTIFY_request:
+ /* Q.2971:Call-Control-U 18/39 */
+ /* Q.2971:Call-Control-N 19/39 */
+ unx_notify_request(c, msg, cookie);
+ break;
+
+ case SIGC_STATUS_ENQUIRY_request:
+ /* Q.2971:Call-Control-U 31/39 */
+ /* Q.2971:Call-Control-N 32/39 */
+ unx_status_enquiry_request(c, msg, cookie);
+ break;
+
+ case SIGC_ADD_PARTY_request:
+ if (c->cstate == CALLST_U4 || c->cstate == CALLST_U10 ||
+ c->cstate == CALLST_N7 || c->cstate == CALLST_N10) {
+ /* Q.2971:Call-Control-U 9-10/39 (U4) */
+ /* Q.2971:Call-Control-U 21/39 (U10) */
+ /* Q.2971:Call-Control-N 12/39 (N7) */
+ /* Q.2971:Call-Control-N 22/39 (N10) */
+ unx_add_party_request(c, msg, cookie);
+ break;
+ }
+ VERBOSE(c->uni, UNI_FAC_ERR, 1, "add-party.request in cs=%s",
+ callstates[c->cstate].name);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
+ uni_msg_destroy(msg);
+ break;
+
+ case SIGC_PARTY_ALERTING_request:
+ if (c->cstate == CALLST_U7 || c->cstate == CALLST_U8 ||
+ c->cstate == CALLST_U10 ||
+ c->cstate == CALLST_N4 || c->cstate == CALLST_N10) {
+ /* Q.2971:Call-Control-U 14/39 U7 */
+ /* Q.2971:Call-Control-U 15/39 U8 */
+ /* Q.2971:Call-Control-U 21/39 U10 */
+ /* Q.2971:Call-Control-N 8/39 N4 */
+ /* Q.2971:Call-Control-N 22/39 N10 */
+ unx_party_alerting_request(c, msg, cookie);
+ break;
+ }
+ VERBOSE(c->uni, UNI_FAC_ERR, 1,
+ "party-alerting.request in cs=%s",
+ callstates[c->cstate].name);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
+ uni_msg_destroy(msg);
+ break;
+
+ case SIGC_ADD_PARTY_ACK_request:
+ if (c->cstate == CALLST_U10 || c->cstate == CALLST_N10) {
+ /* Q.2971:Call-Control-U 21/39 (U10) */
+ /* Q.2971:Call-Control-N 22/39 (N10)*/
+ un10_add_party_ack_request(c, msg, cookie);
+ break;
+ }
+ VERBOSE(c->uni, UNI_FAC_ERR, 1,
+ "add-party-ack.request in cs=%s",
+ callstates[c->cstate].name);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
+ uni_msg_destroy(msg);
+ break;
+
+ case SIGC_ADD_PARTY_REJ_request:
+ if (c->cstate == CALLST_U7 || c->cstate == CALLST_U8 ||
+ c->cstate == CALLST_U10 ||
+ c->cstate == CALLST_N4 || c->cstate == CALLST_N10) {
+ /* Q.2971:Call-Control-U 14/39 U7 */
+ /* Q.2971:Call-Control-U 15/39 U8 */
+ /* Q.2971:Call-Control-U 21/39 U10 */
+ /* Q.2971:Call-Control-N 8/39 N4 */
+ /* Q.2971:Call-Control-N 22/39 N10 */
+ unx_add_party_rej_request(c, msg, cookie);
+ break;
+ }
+ VERBOSE(c->uni, UNI_FAC_ERR, 1,
+ "add-party-rej.request in cs=%s",
+ callstates[c->cstate].name);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
+ uni_msg_destroy(msg);
+ break;
+
+ case SIGC_DROP_PARTY_request:
+ if (c->cstate != CALLST_U11 && c->cstate != CALLST_U12 &&
+ c->cstate != CALLST_N11 && c->cstate != CALLST_N12 &&
+ c->cstate != CALLST_NULL) {
+ /* Q.2971:Call-Control-U 21/39 U10 */
+ /* Q.2971:Call-Control-U 26/39 U1-U9 */
+ /* Q.2971:Call-Control-N 22/39 N10 */
+ /* Q.2971:Call-Control-N 27/39 N1-N9 */
+ unx_drop_party_request(c, msg, cookie);
+ break;
+ }
+ VERBOSE(c->uni, UNI_FAC_ERR, 1, "drop-party.request in cs=%s",
+ callstates[c->cstate].name);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
+ uni_msg_destroy(msg);
+ break;
+
+ case SIGC_DROP_PARTY_ACK_request:
+ if (c->cstate != CALLST_U11 && c->cstate != CALLST_U12 &&
+ c->cstate != CALLST_N11 && c->cstate != CALLST_N12 &&
+ c->cstate != CALLST_NULL) {
+ /* Q.2971:Call-Control-U 21/39 U10 */
+ /* Q.2971:Call-Control-U 26/39 U1-U9 */
+ /* Q.2971:Call-Control-N 22/39 N10 */
+ /* Q.2971:Call-Control-N 27/39 N1-N9 */
+ unx_drop_party_ack_request(c, msg, cookie);
+ break;
+ }
+ VERBOSE(c->uni, UNI_FAC_ERR, 1,
+ "drop-party-ack.request in cs=%s",
+ callstates[c->cstate].name);
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
+ uni_msg_destroy(msg);
+ break;
+
+ case SIGC_ABORT_CALL_request:
+ {
+ struct uni *uni = c->uni;
+
+ uni_destroy_call(c, 0);
+ uniapi_uni_error(uni, UNIAPI_OK, cookie, UNI_CALLSTATE_U0);
+ break;
+ }
+
+ /*
+ * Timers
+ */
+ case SIGC_T301:
+ if (c->cstate == CALLST_U4 || c->cstate == CALLST_N7) {
+ /* Q.2971:Call-Control-U Missing */
+ /* Q.2971:Call-Control-N 14/39 */
+ u4n7_t301(c);
+ break;
+ }
+ VERBOSE(c->uni, UNI_FAC_ERR, 1, "T301 in cs=%s",
+ callstates[c->cstate].name);
+ break;
+
+ case SIGC_T303:
+ if (c->cstate == CALLST_U1 || c->cstate == CALLST_N6) {
+ /* Q.2971:Call-Control-U 6/39 */
+ /* Q.2971:Call-Control-N 11/39 */
+ u1n6_t303(c);
+ break;
+ }
+ VERBOSE(c->uni, UNI_FAC_ERR, 1, "T303 in cs=%s",
+ callstates[c->cstate].name);
+ break;
+
+ case SIGC_T308:
+ if (c->cstate == CALLST_U11 || c->cstate == CALLST_N12) {
+ /* Q.2971:Call-Control-U 28/39 */
+ /* Q.2971:Call-Control-N 30/39 */
+ u11n12_t308(c);
+ break;
+ }
+ VERBOSE(c->uni, UNI_FAC_ERR, 1, "T308 in cs=%s",
+ callstates[c->cstate].name);
+ break;
+
+ case SIGC_T310:
+ if (c->cstate == CALLST_U3 || c->cstate == CALLST_N9) {
+ /* Q.2971:Call-Control-U 7/39 */
+ /* Q.2971:Call-Control-N 17/39 */
+ u3n9_t310(c);
+ break;
+ }
+ VERBOSE(c->uni, UNI_FAC_ERR, 1, "T310 in cs=%s",
+ callstates[c->cstate].name);
+ break;
+
+ case SIGC_T313:
+ if (c->cstate == CALLST_U8) {
+ /* Q.2971:Call-Control-U 15/39 */
+ u8_t313(c);
+ break;
+ }
+ VERBOSE(c->uni, UNI_FAC_ERR, 1, "T313 in cs=%s",
+ callstates[c->cstate].name);
+ break;
+
+ case SIGC_T322:
+ /* Q.2971:Call-Control-U 34/39 */
+ /* Q.2971:Call-Control-N 35/39 */
+ unx_t322(c);
+ break;
+
+ case SIGC_CALL_DELETE:
+ CALL_FREE(c);
+ break;
+
+ /*
+ * Party-Control
+ */
+ case SIGC_DROP_PARTY_indication:
+ if (c->uni->proto == UNIPROTO_UNI40U)
+ /* Q.2971:Call-Control-U 23/39 */
+ ux_drop_party_indication(c, msg);
+ else
+ /* Q.2971:Call-Control-N 23/39 */
+ nx_drop_party_indication(c, msg);
+ break;
+
+ case SIGC_DROP_PARTY_ACK_indication:
+ if (c->uni->proto == UNIPROTO_UNI40U)
+ /* Q.2971:Call-Control-U 23/39 */
+ ux_drop_party_ack_indication(c, msg);
+ else
+ /* Q.2971:Call-Control-N 23/39 */
+ nx_drop_party_ack_indication(c, msg);
+ break;
+
+ case SIGC_ADD_PARTY_REJ_indication:
+ if (c->uni->proto == UNIPROTO_UNI40U)
+ /* Q.2971:Call-Control-U 23/39 */
+ ux_add_party_rej_indication(c, msg);
+ else
+ /* Q.2971:Call-Control-N 23/39 */
+ nx_add_party_rej_indication(c, msg);
+ break;
+
+
+ case SIGC_SEND_DROP_PARTY:
+ /* Q.2971:Call-Control-U 21/39 */
+ /* Q.2971:Call-Control-U 25/39 */
+ if (uni_party_act_count(c, 2) != 0)
+ (void)uni_send_output(u, c->uni);
+ else if(c->cstate != CALLST_U11) {
+ c->uni->cause = u->u.drop_party.cause;
+ clear_callD(c);
+ }
+ UNI_FREE(u);
+ break;
+
+ case SIGC_SEND_DROP_PARTY_ACK:
+ /* Q.2971:Call-Control-U 21/39 */
+ /* Q.2971:Call-Control-U 25/39 */
+ if (uni_party_act_count(c, 2) != 0)
+ (void)uni_send_output(u, c->uni);
+ else if (c->cstate != CALLST_U11) {
+ c->uni->cause = u->u.drop_party_ack.cause;
+ clear_callD(c);
+ }
+ UNI_FREE(u);
+ break;
+
+ case SIGC_SEND_ADD_PARTY_REJ:
+ /* Q.2971:Call-Control-U 21/39 */
+ /* Q.2971:Call-Control-U 24/39 */
+ unx_send_add_party_rej(c, u);
+ break;
+
+ case SIGC_SEND_STATUS_ENQ:
+ /* Q.2971:Call-Control-U 21/39 */
+ /* Q.2971:Call-Control-U 25/39 */
+ unx_send_party_status_enq(c, u);
+ break;
+
+ case SIGC_PARTY_DESTROYED:
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_PARTY_DESTROYED, cookie, msg);
+ break;
+
+ case SIGC_END:
+ break;
+ }
+
+ return;
+
+ drop:
+ /*
+ * This is for SAAL message signals that should be dropped.
+ */
+ uni_msg_destroy(msg);
+ UNI_FREE(u);
+}
+
+/**********************************************************************/
+
+/*
+ * Timeout functions
+ */
+static void
+t308_func(struct call *c)
+{
+ uni_enq_call(c, SIGC_T308, 0, NULL, NULL);
+}
+static void
+t303_func(struct call *c)
+{
+ uni_enq_call(c, SIGC_T303, 0, NULL, NULL);
+}
+static void
+t301_func(struct call *c)
+{
+ uni_enq_call(c, SIGC_T301, 0, NULL, NULL);
+}
+static void
+t310_func(struct call *c)
+{
+ uni_enq_call(c, SIGC_T310, 0, NULL, NULL);
+}
+static void
+t313_func(struct call *c)
+{
+ uni_enq_call(c, SIGC_T313, 0, NULL, NULL);
+}
+
+static void
+t322_func(struct call *c)
+{
+ uni_enq_call(c, SIGC_T322, 0, NULL, NULL);
+}
+
+/**********************************************************************/
+
+/*
+ * Check whether the peer state is compatible with our state.
+ * Return the new callstate we should go to (either U0 or the current
+ * state).
+ * None of the state is U0 here. My state is not U11 or U12.
+ *
+ * Well, this turns out to be not so easy: the status enquiry could have
+ * been sent before we changed into the current state - the status will
+ * report a previous state without anything been lost.
+ *
+ * Incoming states are incompatible with outgoing states. Everything is ok.
+ */
+static enum call_state
+state_compat(struct call *c, enum uni_callstate peer)
+{
+ if ((c->cstate == CALLST_U1 ||
+ c->cstate == CALLST_U3 ||
+ c->cstate == CALLST_U4) &&
+ (peer == UNI_CALLSTATE_N6 ||
+ peer == UNI_CALLSTATE_N7 ||
+ peer == UNI_CALLSTATE_N8 ||
+ peer == UNI_CALLSTATE_N9))
+ return (CALLST_NULL);
+
+ if ((c->cstate == CALLST_N6 ||
+ c->cstate == CALLST_N7 ||
+ c->cstate == CALLST_N8 ||
+ c->cstate == CALLST_N9) &&
+ (peer == UNI_CALLSTATE_U1 ||
+ peer == UNI_CALLSTATE_U3 ||
+ peer == UNI_CALLSTATE_U4))
+ return (CALLST_NULL);
+
+ if ((peer == UNI_CALLSTATE_N1 ||
+ peer == UNI_CALLSTATE_N3 ||
+ peer == UNI_CALLSTATE_N4) &&
+ (c->cstate == CALLST_U6 ||
+ c->cstate == CALLST_U7 ||
+ c->cstate == CALLST_U8 ||
+ c->cstate == CALLST_N9))
+ return (CALLST_NULL);
+
+ if ((peer == UNI_CALLSTATE_U6 ||
+ peer == UNI_CALLSTATE_U7 ||
+ peer == UNI_CALLSTATE_U8 ||
+ peer == UNI_CALLSTATE_U9) &&
+ (c->cstate == CALLST_N1 ||
+ c->cstate == CALLST_N3 ||
+ c->cstate == CALLST_N4))
+ return (CALLST_NULL);
+
+ return (c->cstate);
+}
diff --git a/sys/contrib/ngatm/netnatm/sig/sig_coord.c b/sys/contrib/ngatm/netnatm/sig/sig_coord.c
new file mode 100644
index 0000000..bbdd723
--- /dev/null
+++ b/sys/contrib/ngatm/netnatm/sig/sig_coord.c
@@ -0,0 +1,1171 @@
+/*
+ * 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/sig/sig_coord.c,v 1.6 2003/09/24 10:27:50 hbb Exp $
+ *
+ * Coordinator
+ */
+
+#include <netnatm/unimsg.h>
+#include <netnatm/saal/sscfudef.h>
+#include <netnatm/msg/unistruct.h>
+#include <netnatm/msg/unimsglib.h>
+#include <netnatm/sig/uni.h>
+
+#include <netnatm/sig/unipriv.h>
+#include <netnatm/sig/unimkmsg.h>
+
+#define STR(S) [S] #S
+static const char *const cunames[] = {
+ STR(CU_STAT0),
+ STR(CU_STAT1),
+ STR(CU_STAT2),
+ STR(CU_STAT3),
+};
+
+#define DEF_PRIV_SIG(NAME, FROM) [SIG##NAME] "SIG"#NAME,
+static const char *const coord_sigs[] = {
+ DEF_COORD_SIGS
+};
+#undef DEF_PRIV_SIG
+
+static void sig_all_calls(struct uni *, u_int sig);
+static void set_custat(struct uni *, enum cu_stat);
+
+static void input_dummy(struct uni *uni, struct uni_msg *m, struct uni_all *u);
+static void input_global(struct uni *uni, struct uni_msg *m, struct uni_all *u);
+static void input_unknown(struct uni *uni, struct uni_msg *m, struct uni_all *u);
+static void input_cobi(struct call *c, struct uni_msg *m, struct uni_all *u);
+static void input_call(struct call *c, struct uni_msg *m, struct uni_all *u);
+
+TIMER_FUNC_UNI(t309, t309_func)
+
+/*
+ * All those 'bogus signal' printouts are not specified in the SDLs.
+ */
+
+
+/*
+ * SAAL-ESTABLISH.indication
+ *
+ * This means either a resynchronisation or error-recovery or
+ * an incoming SSCOP connection.
+ */
+static void
+coord_saal_establish_indication(struct uni *uni)
+{
+ switch (uni->custat) {
+
+ case CU_STAT0: /* Q.2931:Coord-U 4/10 */
+ case CU_STAT3: /* Q.2931:Coord-U 5/10 */
+ sig_all_calls(uni, SIGC_LINK_ESTABLISH_indication);
+ set_custat(uni, CU_STAT3);
+ break;
+
+ case CU_STAT1:
+ case CU_STAT2:
+ VERBOSE0(uni, UNI_FAC_COORD,
+ "signal saal_establish.indication in CU%u", uni->custat);
+ break;
+
+ default:
+ ASSERT(0, ("CU_STAT*"));
+ }
+}
+
+/*
+ * SAAL-ESTABLISH.confirm
+ */
+static void
+coord_saal_establish_confirm(struct uni *uni)
+{
+ switch (uni->custat) {
+
+ case CU_STAT0:
+ case CU_STAT2:
+ VERBOSE0(uni, UNI_FAC_COORD,
+ "signal saal_establish.confirm in CU%u", uni->custat);
+ break;
+
+ case CU_STAT1:
+ /*
+ * Q.2931:Co-ord-U 4/10
+ */
+ TIMER_STOP_UNI(uni, t309);
+ sig_all_calls(uni, SIGC_LINK_ESTABLISH_confirm);
+ uni->funcs->uni_output(uni, uni->arg,
+ UNIAPI_LINK_ESTABLISH_confirm, 0, NULL);
+ set_custat(uni, CU_STAT3);
+ break;
+
+ case CU_STAT3:
+ /*
+ * Q.2931:Coord-U 5/10
+ */
+ sig_all_calls(uni, SIGC_LINK_ESTABLISH_confirm);
+ uni->funcs->uni_output(uni, uni->arg,
+ UNIAPI_LINK_ESTABLISH_confirm, 0, NULL);
+ break;
+
+ default:
+ ASSERT(0, ("CU_STAT*"));
+ }
+}
+
+/*
+ * SAAL-RELEASE.confirm
+ */
+static void
+coord_saal_release_confirm(struct uni *uni)
+{
+ switch (uni->custat) {
+
+ case CU_STAT0:
+ case CU_STAT1:
+ case CU_STAT3:
+ VERBOSE0(uni, UNI_FAC_COORD,
+ "signal saal_release.confirm in CU%u", uni->custat);
+ break;
+
+ case CU_STAT2:
+ /*
+ * Q.2931:Coord-U 5/10
+ */
+ uni->funcs->uni_output(uni, uni->arg,
+ UNIAPI_LINK_RELEASE_confirm, 0, NULL);
+ set_custat(uni, CU_STAT0);
+ break;
+
+ default:
+ ASSERT(0, ("CU_STAT*"));
+ }
+}
+
+/*
+ * SAAL failure.
+ */
+static void
+coord_saal_release_indication(struct uni *uni)
+{
+ switch (uni->custat) {
+
+ case CU_STAT0:
+ case CU_STAT2:
+ VERBOSE0(uni, UNI_FAC_COORD,
+ "signal saal_release.indication in CU%u", uni->custat);
+ break;
+
+ case CU_STAT1:
+ case CU_STAT3:
+ /*
+ * Q.2931:Coord-U 4/10
+ * Q.2931:Coord-U 5/10
+ */
+ sig_all_calls(uni, SIGC_LINK_RELEASE_indication);
+ set_custat(uni, CU_STAT0);
+ break;
+
+ default:
+ ASSERT(0, ("CU_STAT*"));
+ }
+}
+
+/*
+ * Link-establish.request from USER. This can also come from
+ * a call instance. In this case 'cookie' is zero.
+ */
+static void
+coord_link_establish_request(struct uni *uni, u_int32_t cookie)
+{
+ switch (uni->custat) {
+
+ case CU_STAT0:
+ /*
+ * Q.2931:Coord-U 4/10
+ */
+ uni->funcs->saal_output(uni, uni->arg,
+ SAAL_ESTABLISH_request, NULL);
+ if (!TIMER_ISACT(uni, t309))
+ TIMER_START_UNI(uni, t309, uni->timer309);
+ set_custat(uni, CU_STAT1);
+ if (cookie)
+ uniapi_uni_error(uni, UNIAPI_OK, cookie, 0);
+ break;
+
+ case CU_STAT1:
+ /*
+ * Q.2931:Coord-U 4/10
+ * This is probably missing from the delay field.
+ */
+ uni_delenq_coord(uni, SIGO_LINK_ESTABLISH_request,
+ cookie, NULL);
+ break;
+
+ case CU_STAT2:
+ uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0);
+ if (cookie == 0)
+ VERBOSE0(uni, UNI_FAC_COORD,
+ "signal link-establish.request in CU%u",
+ uni->custat);
+ break;
+
+ case CU_STAT3:
+ /*
+ * Q.2931:Coord-U 5/10
+ */
+ uni->funcs->uni_output(uni, uni->arg,
+ UNIAPI_LINK_ESTABLISH_confirm, 0, NULL);
+ uniapi_uni_error(uni, UNIAPI_OK, cookie, 0);
+ break;
+
+ default:
+ ASSERT(0, ("CU_STAT*"));
+ }
+}
+
+/*
+ * Link-release.request from user
+ */
+static void
+coord_link_release_request(struct uni *uni, u_int cookie)
+{
+ switch (uni->custat) {
+
+ case CU_STAT0:
+ case CU_STAT1:
+ case CU_STAT2:
+ uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0);
+ break;
+
+ case CU_STAT3:
+ /*
+ * Q.2931:Coord-U 5/10
+ */
+ uni->funcs->saal_output(uni, uni->arg,
+ SAAL_RELEASE_request, NULL);
+ set_custat(uni, CU_STAT2);
+ uniapi_uni_error(uni, UNIAPI_OK, cookie, 0);
+ break;
+
+ default:
+ ASSERT(0, ("CU_STAT*"));
+ }
+}
+
+/*
+ * T309 timeout signal
+ */
+static void
+coord_t309(struct uni *uni)
+{
+ switch (uni->custat) {
+
+ case CU_STAT0:
+ case CU_STAT1:
+ /*
+ * Q.2931:Coord-U 4/10
+ */
+ sig_all_calls(uni, SIGC_LINK_ESTABLISH_ERROR_indication);
+ set_custat(uni, CU_STAT0);
+ /* this is not in the SDLs, but how will the call control
+ * know, that starting the LINK has failed otherwise? */
+ uni->funcs->uni_output(uni, uni->arg,
+ UNIAPI_LINK_RELEASE_confirm, 0, NULL);
+ break;
+
+ case CU_STAT2:
+ case CU_STAT3:
+ VERBOSE0(uni, UNI_FAC_COORD,
+ "signal T309 in CU%u", uni->custat);
+ break;
+
+ default:
+ ASSERT(0, ("CU_STAT*"));
+ }
+}
+
+/*
+ * Message from SAAL
+ */
+static void
+coord_saal_data_indication(struct uni *uni, struct uni_msg *m)
+{
+ struct uni_all *u;
+ struct call *c;
+
+ memset(&uni->cause, 0, sizeof(uni->cause));
+ if ((u = UNI_ALLOC()) == NULL) {
+ uni_msg_destroy(m);
+ return;
+ }
+ if (uni_decode_head(m, u, &uni->cx)) {
+ VERBOSE(uni, UNI_FAC_COORD, 2, "bogus message - ignored");
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+ return;
+ }
+ if (u->u.hdr.cref.cref == CREF_DUMMY) {
+ if (uni->cx.q2932) {
+ input_dummy(uni, m, u);
+ } else {
+ VERBOSE(uni, UNI_FAC_COORD, 2, "dummy cref - ignored");
+ UNI_FREE(u);
+ uni_msg_destroy(m);
+ }
+ return;
+ }
+
+ if (u->u.hdr.cref.cref == CREF_GLOBAL)
+ input_global(uni, m, u);
+ else if ((c = uni_find_call(uni, &u->u.hdr.cref)) == NULL)
+ input_unknown(uni, m, u);
+ else if (c->type == CALL_COBI)
+ input_cobi(c, m, u);
+ else
+ input_call(c, m, u);
+}
+
+/*
+ * Message with global call reference
+ *
+ * Q.2931:Coord-U (X) 7/10
+ */
+static void
+input_global(struct uni *uni, struct uni_msg *m, struct uni_all *u)
+{
+ VERBOSE(uni, UNI_FAC_COORD, 2, "GLOB MTYPE = %x", u->mtype);
+
+ switch (u->mtype) {
+
+ default:
+ /*
+ * Q.2931:Coord-U 7/10
+ * Q.2931: 5.6.3.2e
+ * Amd4: 29e
+ */
+ uni_respond_status(uni, &u->u.hdr.cref,
+ u->u.hdr.cref.flag ? uni->glob_start : uni->glob_respond,
+ UNI_CAUSE_CREF_INV);
+ break;
+
+ case UNI_RESTART:
+ if (u->u.hdr.cref.flag) {
+ /*
+ * Q.2931:Coord-U 7/10 (5.6.3.2h)
+ */
+ uni_respond_status(uni, &u->u.hdr.cref,
+ uni->glob_start, UNI_CAUSE_CREF_INV);
+ break;
+ }
+ uni_enq_resp(uni, SIGR_RESTART, 0, m, u);
+ return;
+
+ case UNI_RESTART_ACK:
+ if (!u->u.hdr.cref.flag) {
+ /*
+ * Q.2931:Coord-U 7/10 (5.6.3.2h)
+ * Note, that the SDL diagram contains an error.
+ * The error with the 'YES' label should go to the
+ * box below 'OTHER'.
+ */
+ uni_respond_status(uni, &u->u.hdr.cref,
+ uni->glob_respond, UNI_CAUSE_CREF_INV);
+ break;
+ }
+ uni_enq_start(uni, SIGS_RESTART_ACK, 0, m, u);
+ return;
+
+ case UNI_STATUS:
+ if (u->u.hdr.cref.flag)
+ uni_enq_start(uni, SIGS_STATUS, 0, m, u);
+ else
+ uni_enq_resp(uni, SIGR_STATUS, 0, m, u);
+ return;
+ }
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+}
+
+/*
+ * Q.2931:Coord-U 8/10
+ *
+ * Message for an unknown call reference
+ */
+static void
+input_unknown(struct uni *uni, struct uni_msg *m, struct uni_all *u)
+{
+ struct uni_all *resp;
+ struct call *c;
+ u_int cause = UNI_CAUSE_CREF_INV;
+
+ VERBOSE(uni, UNI_FAC_COORD, 2, "UNKNOWN MTYPE = %x", u->mtype);
+
+ switch (u->mtype) {
+
+ default:
+ /*
+ * This message type is entirly unknown
+ *
+ * 5.6.4 and 5.7.1 are only when the call is not in the
+ * NULL state. This means, 5.6.3.2a takes over.
+ */
+ break;
+
+ case UNI_SETUP:
+ if (u->u.hdr.cref.flag)
+ /*
+ * 5.6.3.2c
+ */
+ goto drop;
+ if ((c = uni_create_call(uni, u->u.hdr.cref.cref, 0, 0)) != NULL) {
+ uni_enq_call(c, SIGC_SETUP, 0, m, u);
+ return;
+ }
+ goto drop;
+
+ case UNI_RELEASE_COMPL:
+ /*
+ * 5.6.3.2c
+ */
+ goto drop;
+
+ case UNI_STATUS:
+ /*
+ * 5.6.12
+ *
+ * The SDLs don't use the verify procedure and don't
+ * handle the case of an invalid callstate - we
+ * ignore the message, if the callstate is not good.
+ */
+ (void)uni_decode_body(m, u, &uni->cx);
+ if (!IE_ISGOOD(u->u.status.callstate))
+ goto drop;
+ if (u->u.status.callstate.state == UNI_CALLSTATE_U0)
+ goto drop;
+ cause = UNI_CAUSE_MSG_INCOMP;
+ break;
+
+ case UNI_STATUS_ENQ:
+ if ((resp = UNI_ALLOC()) == NULL)
+ goto drop;
+
+ (void)uni_decode_body(m, u, &uni->cx);
+ MK_MSG_RESP(resp, UNI_STATUS, &u->u.hdr.cref);
+ MK_IE_CALLSTATE(resp->u.status.callstate, UNI_CALLSTATE_U0);
+ MK_IE_CAUSE(resp->u.status.cause, UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_STATUS);
+
+ if (IE_ISGOOD(u->u.status_enq.epref)) {
+ /* reflect epref as required by L3MU_PO */
+ resp->u.status.epref = u->u.status_enq.epref;
+ MK_IE_EPREF(resp->u.status.epref,
+ u->u.status_enq.epref.epref,
+ !u->u.status_enq.epref.flag);
+ MK_IE_EPSTATE(resp->u.status.epstate, UNI_EPSTATE_NULL);
+ }
+
+ (void)uni_send_output(resp, uni);
+
+ UNI_FREE(resp);
+ goto drop;
+
+ case UNI_COBISETUP:
+ if (u->u.hdr.cref.flag)
+ /*
+ * 5.6.3.2c (probably)
+ */
+ goto drop;
+ if ((c = uni_create_call(uni, u->u.hdr.cref.cref, 0, 0)) != NULL) {
+ uni_enq_call(c, SIGC_COBISETUP, 0, m, u);
+ return;
+ }
+ goto drop;
+ }
+
+ /*
+ * 5.6.3.2a)
+ *
+ * Respond with a RELEASE COMPLETE
+ */
+ if ((resp = UNI_ALLOC()) == NULL)
+ goto drop;
+
+ MK_MSG_RESP(resp, UNI_RELEASE_COMPL, &u->u.hdr.cref);
+ MK_IE_CAUSE(resp->u.release_compl.cause[0], UNI_CAUSE_LOC_USER, cause);
+ if (uni_diag(cause, UNI_CODING_ITU) == UNI_DIAG_MTYPE)
+ ADD_CAUSE_MTYPE(resp->u.release_compl.cause[0], u->mtype);
+
+ (void)uni_send_output(resp, uni);
+
+ UNI_FREE(resp);
+
+ drop:
+ UNI_FREE(u);
+ uni_msg_destroy(m);
+}
+
+static void
+input_cobi(struct call *c __unused, struct uni_msg *m, struct uni_all *u)
+{
+ /* XXX */
+ UNI_FREE(u);
+ uni_msg_destroy(m);
+}
+
+static void
+input_dummy(struct uni *uni __unused, struct uni_msg *m, struct uni_all *u)
+{
+ /* XXX */
+ UNI_FREE(u);
+ uni_msg_destroy(m);
+}
+
+static void
+input_call(struct call *c, struct uni_msg *m, struct uni_all *u)
+{
+ VERBOSE(c->uni, UNI_FAC_COORD, 2, "CALL MTYPE = %x %d/%s",
+ u->mtype, c->cref, c->mine ? "mine":"his");
+
+ switch (u->mtype) {
+
+ case UNI_SETUP:
+ /*
+ * Ignored
+ */
+ break;
+
+ case UNI_CALL_PROC:
+ uni_enq_call(c, SIGC_CALL_PROC, 0, m, u);
+ return;
+
+ case UNI_ALERTING:
+ uni_enq_call(c, SIGC_ALERTING, 0, m, u);
+ return;
+
+ case UNI_RELEASE:
+ uni_enq_call(c, SIGC_RELEASE, 0, m, u);
+ return;
+
+ case UNI_RELEASE_COMPL:
+ uni_enq_call(c, SIGC_RELEASE_COMPL, 0, m, u);
+ return;
+
+ case UNI_CONNECT:
+ uni_enq_call(c, SIGC_CONNECT, 0, m, u);
+ return;
+
+ case UNI_CONNECT_ACK:
+ uni_enq_call(c, SIGC_CONNECT_ACK, 0, m, u);
+ return;
+
+ case UNI_NOTIFY:
+ uni_enq_call(c, SIGC_NOTIFY, 0, m, u);
+ return;
+
+ case UNI_STATUS:
+ uni_enq_call(c, SIGC_STATUS, 0, m, u);
+ return;
+
+ case UNI_STATUS_ENQ:
+ uni_enq_call(c, SIGC_STATUS_ENQ, 0, m, u);
+ return;
+
+ case UNI_ADD_PARTY:
+ uni_enq_call(c, SIGC_ADD_PARTY, 0, m, u);
+ return;
+
+ case UNI_PARTY_ALERTING:
+ uni_enq_call(c, SIGC_PARTY_ALERTING, 0, m, u);
+ return;
+
+ case UNI_ADD_PARTY_ACK:
+ uni_enq_call(c, SIGC_ADD_PARTY_ACK, 0, m, u);
+ return;
+
+ case UNI_ADD_PARTY_REJ:
+ uni_enq_call(c, SIGC_ADD_PARTY_REJ, 0, m, u);
+ return;
+
+ case UNI_DROP_PARTY:
+ uni_enq_call(c, SIGC_DROP_PARTY, 0, m, u);
+ return;
+
+ case UNI_DROP_PARTY_ACK:
+ uni_enq_call(c, SIGC_DROP_PARTY_ACK, 0, m, u);
+ return;
+
+ default:
+ uni_enq_call(c, SIGC_UNKNOWN, 0, m, u);
+ return;
+ }
+ UNI_FREE(u);
+ uni_msg_destroy(m);
+}
+
+
+/*
+ * This macro tries to implement the delaying behaviour for
+ * message from the API when we are in the Awaiting-Establish state.
+ * In this state, the message is delayed. If we drop back to CU 0,
+ * everything gets unqueued and errors are returned for all that stuff.
+ * If we progess to CUSTAT2 we process the requests.
+ */
+#define COMMON_DELAY(SIG, COOKIE) \
+ if (uni->custat == CU_STAT0 || uni->custat == CU_STAT2) {\
+ uniapi_uni_error(uni, UNIAPI_ERROR_BADCU, \
+ COOKIE, 0); \
+ break; \
+ } \
+ if (uni->custat == CU_STAT1) { \
+ uni_delenq_coord(uni, SIG, COOKIE, msg); \
+ break; \
+ }
+
+/*
+ * Signal handler of the coordinator
+ */
+void
+uni_sig_coord(struct uni *uni, enum coord_sig sig, u_int32_t cookie,
+ struct uni_msg *msg)
+{
+ struct call *c;
+
+ if (sig >= SIGO_END) {
+ VERBOSE(uni, UNI_FAC_ERR, 1, "Signal %d outside of range to "
+ "Coord", sig);
+ if (msg)
+ uni_msg_destroy(msg);
+ return;
+ }
+
+ VERBOSE(uni, UNI_FAC_COORD, 1, "Signal %s in state %s",
+ coord_sigs[sig], cunames[uni->custat]);
+
+ switch (sig) {
+
+ case SIGO_END:
+ break;
+
+ case SIGO_DATA: /* delayed output */
+ if (uni->custat == CU_STAT0 || uni->custat == CU_STAT1)
+ break; /* drop */
+ if (uni->custat == CU_STAT1)
+ uni_delenq_coord(uni, SIGO_DATA, cookie, msg);/* ??? */
+ else
+ uni->funcs->saal_output(uni, uni->arg,
+ SAAL_DATA_request, msg);
+ msg = NULL;
+ break;
+
+ /*
+ * SAAL signals
+ */
+ case SIGO_SAAL_ESTABLISH_indication:
+ coord_saal_establish_indication(uni);
+ break;
+
+ case SIGO_SAAL_ESTABLISH_confirm:
+ coord_saal_establish_confirm(uni);
+ break;
+
+ case SIGO_SAAL_RELEASE_confirm:
+ coord_saal_release_confirm(uni);
+ break;
+
+ case SIGO_SAAL_RELEASE_indication:
+ coord_saal_release_indication(uni);
+ break;
+
+ case SIGO_SAAL_DATA_indication:
+ coord_saal_data_indication(uni, msg);
+ msg = NULL;
+ break;
+
+ case SIGO_SAAL_UDATA_indication:
+ VERBOSE0(uni, UNI_FAC_ERR, "SAAL_UDATA_indication");
+ break;
+
+ /*
+ * Signals from USER
+ */
+ case SIGO_LINK_ESTABLISH_request:
+ coord_link_establish_request(uni, cookie);
+ break;
+
+ case SIGO_LINK_RELEASE_request:
+ coord_link_release_request(uni, cookie);
+ break;
+
+ case SIGO_RESET_request:
+ uni_enq_start(uni, SIGS_RESET_request, cookie, msg, NULL);
+ msg = NULL;
+ if (uni->custat == CU_STAT0) {
+ uni->funcs->saal_output(uni, uni->arg,
+ SAAL_ESTABLISH_request, NULL);
+ if (!TIMER_ISACT(uni, t309))
+ TIMER_START_UNI(uni, t309, uni->timer309);
+ set_custat(uni, CU_STAT1);
+ }
+ break;
+
+ case SIGO_RESET_ERROR_response:
+ COMMON_DELAY(SIGO_RESET_ERROR_response, cookie);
+ uni_enq_resp(uni, SIGR_RESET_ERROR_response, cookie, msg, NULL);
+ msg = NULL;
+ break;
+
+ case SIGO_RESET_response:
+ COMMON_DELAY(SIGO_RESET_response, cookie);
+ uni_enq_resp(uni, SIGR_RESET_response, cookie, msg, NULL);
+ msg = NULL;
+ break;
+
+ case SIGO_SETUP_request:
+ if ((c = uni_create_new_call(uni, cookie)) != NULL) {
+ uni_enq_call(c, SIGC_SETUP_request, cookie, msg, NULL);
+ msg = NULL;
+ if (uni->custat == CU_STAT0) {
+ uni->funcs->saal_output(uni, uni->arg,
+ SAAL_ESTABLISH_request, NULL);
+ if (!TIMER_ISACT(uni, t309))
+ TIMER_START_UNI(uni, t309, uni->timer309);
+ set_custat(uni, CU_STAT1);
+ }
+ } else {
+ uniapi_uni_error(uni, UNIAPI_ERROR_NOMEM, cookie,
+ UNI_CALLSTATE_U0);
+ }
+ break;
+
+ case SIGO_PROCEEDING_request:
+ {
+ struct uniapi_proceeding_request *arg =
+ uni_msg_rptr(msg, struct uniapi_proceeding_request *);
+
+ COMMON_DELAY(SIGO_PROCEEDING_request, cookie);
+ if ((c = uni_find_call(uni, &arg->call_proc.hdr.cref)) != NULL) {
+ uni_enq_call(c, SIGC_PROCEEDING_request, cookie, msg, NULL);
+ msg = NULL;
+ } else {
+ uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
+ UNI_CALLSTATE_U0);
+ }
+ break;
+ }
+
+ case SIGO_ALERTING_request:
+ {
+ struct uniapi_alerting_request *arg =
+ uni_msg_rptr(msg, struct uniapi_alerting_request *);
+
+ COMMON_DELAY(SIGO_ALERTING_request, cookie);
+ if ((c = uni_find_call(uni, &arg->alerting.hdr.cref)) != NULL) {
+ uni_enq_call(c, SIGC_ALERTING_request, cookie, msg, NULL);
+ msg = NULL;
+ } else {
+ uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
+ UNI_CALLSTATE_U0);
+ }
+ break;
+ }
+
+ case SIGO_SETUP_response:
+ {
+ struct uniapi_setup_response *arg =
+ uni_msg_rptr(msg, struct uniapi_setup_response *);
+
+ COMMON_DELAY(SIGO_SETUP_response, cookie);
+ if ((c = uni_find_call(uni, &arg->connect.hdr.cref)) != NULL) {
+ uni_enq_call(c, SIGC_SETUP_response, cookie, msg, NULL);
+ msg = NULL;
+ } else {
+ uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
+ UNI_CALLSTATE_U0);
+ }
+ break;
+ }
+
+ case SIGO_SETUP_COMPLETE_request:
+ {
+ struct uniapi_setup_complete_request *arg =
+ uni_msg_rptr(msg, struct uniapi_setup_complete_request *);
+
+ COMMON_DELAY(SIGO_SETUP_COMPLETE_request, cookie);
+ if ((c = uni_find_call(uni, &arg->connect_ack.hdr.cref)) != NULL) {
+ uni_enq_call(c, SIGC_SETUP_COMPLETE_request,
+ cookie, msg, NULL);
+ msg = NULL;
+ } else {
+ uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
+ UNI_CALLSTATE_U0);
+ }
+ break;
+ }
+
+ case SIGO_RELEASE_request:
+ {
+ struct uniapi_release_request *arg =
+ uni_msg_rptr(msg, struct uniapi_release_request *);
+
+ COMMON_DELAY(SIGO_RELEASE_request, cookie);
+ if ((c = uni_find_call(uni, &arg->release.hdr.cref)) != NULL) {
+ uni_enq_call(c, SIGC_RELEASE_request, cookie, msg, NULL);
+ msg = NULL;
+ } else {
+ uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
+ UNI_CALLSTATE_U0);
+ }
+ break;
+ }
+
+ case SIGO_RELEASE_response:
+ {
+ struct uniapi_release_response *arg =
+ uni_msg_rptr(msg, struct uniapi_release_response *);
+
+ COMMON_DELAY(SIGO_RELEASE_response, cookie);
+ if ((c = uni_find_call(uni, &arg->release_compl.hdr.cref)) != NULL) {
+ uni_enq_call(c, SIGC_RELEASE_response, cookie, msg, NULL);
+ msg = NULL;
+ } else {
+ uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
+ UNI_CALLSTATE_U0);
+ }
+ break;
+ }
+
+ case SIGO_NOTIFY_request:
+ {
+ struct uniapi_notify_request *arg =
+ uni_msg_rptr(msg, struct uniapi_notify_request *);
+
+ COMMON_DELAY(SIGO_NOTIFY_request, cookie);
+ if ((c = uni_find_call(uni, &arg->notify.hdr.cref)) != NULL) {
+ uni_enq_call(c, SIGC_NOTIFY_request, cookie, msg, NULL);
+ msg = NULL;
+ } else {
+ uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
+ UNI_CALLSTATE_U0);
+ }
+ break;
+ }
+
+ case SIGO_STATUS_ENQUIRY_request:
+ {
+ struct uniapi_status_enquiry_request *arg =
+ uni_msg_rptr(msg, struct uniapi_status_enquiry_request *);
+
+ COMMON_DELAY(SIGO_STATUS_ENQUIRY_request, cookie);
+ if ((c = uni_find_call(uni, &arg->cref)) != NULL) {
+ uni_enq_call(c, SIGC_STATUS_ENQUIRY_request, cookie, msg, NULL);
+ msg = NULL;
+ } else {
+ uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
+ UNI_CALLSTATE_U0);
+ }
+ break;
+ }
+
+ case SIGO_ADD_PARTY_request:
+ {
+ struct uniapi_add_party_request *arg =
+ uni_msg_rptr(msg, struct uniapi_add_party_request *);
+
+ COMMON_DELAY(SIGO_ADD_PARTY_request, cookie);
+ if ((c = uni_find_call(uni, &arg->add.hdr.cref)) != NULL) {
+ if (c->type != CALL_ROOT) {
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_CTYPE,
+ cookie);
+ break;
+ }
+ uni_enq_call(c, SIGC_ADD_PARTY_request, cookie, msg, NULL);
+ msg = NULL;
+ } else {
+ uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
+ UNI_CALLSTATE_U0);
+ }
+ break;
+ }
+
+ case SIGO_PARTY_ALERTING_request:
+ {
+ struct uniapi_party_alerting_request *arg =
+ uni_msg_rptr(msg, struct uniapi_party_alerting_request *);
+
+ COMMON_DELAY(SIGO_PARTY_ALERTING_request, cookie);
+ if ((c = uni_find_call(uni, &arg->alert.hdr.cref)) != NULL) {
+ if (c->type != CALL_LEAF) {
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_CTYPE,
+ cookie);
+ break;
+ }
+ uni_enq_call(c, SIGC_PARTY_ALERTING_request, cookie, msg, NULL);
+ msg = NULL;
+ } else {
+ uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
+ UNI_CALLSTATE_U0);
+ }
+ break;
+ }
+
+ case SIGO_ADD_PARTY_ACK_request:
+ {
+ struct uniapi_add_party_ack_request *arg =
+ uni_msg_rptr(msg, struct uniapi_add_party_ack_request *);
+
+ COMMON_DELAY(SIGO_ADD_PARTY_ACK_request, cookie);
+ if ((c = uni_find_call(uni, &arg->ack.hdr.cref)) != NULL) {
+ if (c->type != CALL_LEAF) {
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_CTYPE,
+ cookie);
+ break;
+ }
+ uni_enq_call(c, SIGC_ADD_PARTY_ACK_request, cookie, msg, NULL);
+ msg = NULL;
+ } else {
+ uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
+ UNI_CALLSTATE_U0);
+ }
+ break;
+ }
+
+ case SIGO_ADD_PARTY_REJ_request:
+ {
+ struct uniapi_add_party_rej_request *arg =
+ uni_msg_rptr(msg, struct uniapi_add_party_rej_request *);
+
+ COMMON_DELAY(SIGO_ADD_PARTY_REJ_request, cookie);
+ if ((c = uni_find_call(uni, &arg->rej.hdr.cref)) != NULL) {
+ if (c->type != CALL_LEAF) {
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_CTYPE,
+ cookie);
+ break;
+ }
+ uni_enq_call(c, SIGC_ADD_PARTY_REJ_request, cookie, msg, NULL);
+ msg = NULL;
+ } else {
+ uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
+ UNI_CALLSTATE_U0);
+ }
+ break;
+ }
+
+ case SIGO_DROP_PARTY_request:
+ {
+ struct uniapi_drop_party_request *arg =
+ uni_msg_rptr(msg, struct uniapi_drop_party_request *);
+
+ COMMON_DELAY(SIGO_DROP_PARTY_request, cookie);
+ if ((c = uni_find_call(uni, &arg->drop.hdr.cref)) != NULL) {
+ if (c->type != CALL_ROOT && c->type != CALL_LEAF) {
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_CTYPE,
+ cookie);
+ break;
+ }
+ uni_enq_call(c, SIGC_DROP_PARTY_request, cookie, msg, NULL);
+ msg = NULL;
+ } else {
+ uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
+ UNI_CALLSTATE_U0);
+ }
+ break;
+ }
+
+ case SIGO_DROP_PARTY_ACK_request:
+ {
+ struct uniapi_drop_party_ack_request *arg =
+ uni_msg_rptr(msg, struct uniapi_drop_party_ack_request *);
+
+ COMMON_DELAY(SIGO_DROP_PARTY_ACK_request, cookie);
+ if ((c = uni_find_call(uni, &arg->ack.hdr.cref)) != NULL) {
+ if (c->type != CALL_ROOT && c->type != CALL_LEAF) {
+ uniapi_call_error(c, UNIAPI_ERROR_BAD_CTYPE,
+ cookie);
+ break;
+ }
+ uni_enq_call(c, SIGC_DROP_PARTY_ACK_request, cookie, msg, NULL);
+ msg = NULL;
+ } else {
+ uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
+ UNI_CALLSTATE_U0);
+ }
+ break;
+ }
+
+ case SIGO_ABORT_CALL_request:
+ {
+ struct uniapi_abort_call_request *arg =
+ uni_msg_rptr(msg, struct uniapi_abort_call_request *);
+
+ if ((c = uni_find_call(uni, &arg->cref)) != NULL) {
+ uni_enq_call(c, SIGC_ABORT_CALL_request, cookie, NULL, NULL);
+ } else {
+ uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
+ UNI_CALLSTATE_U0);
+ }
+ break;
+ }
+
+ /*
+ * Call-Control
+ */
+ case SIGO_CALL_DESTROYED:
+ uni->funcs->uni_output(uni, uni->arg,
+ UNIAPI_CALL_DESTROYED, 0, msg);
+ msg = NULL;
+ break;
+
+ /*
+ * ResetRespond
+ */
+ case SIGO_RESET_indication:
+ uni->funcs->uni_output(uni, uni->arg,
+ UNIAPI_RESET_indication, 0, msg);
+ msg = NULL;
+ break;
+
+ /*
+ * Timeouts
+ */
+ case SIGO_T309:
+ coord_t309(uni);
+ break;
+
+ }
+ if (msg != NULL)
+ uni_msg_destroy(msg);
+}
+
+/*
+ * Send a signal to all call instances
+ */
+static void
+sig_all_calls(struct uni *uni, u_int sig)
+{
+ struct call *call;
+
+ TAILQ_FOREACH(call, &uni->calls, link)
+ uni_enq_call(call, sig, 0, NULL, NULL);
+}
+
+/*
+ * Set a new coordinator state - this moves all delayed coordinator
+ * signals from the delayed queue to the signal queue.
+ */
+static int
+cufilt(struct sig *s, void *arg __unused)
+{
+ return (s->type == SIG_COORD);
+}
+
+static void
+set_custat(struct uni *uni, enum cu_stat nstate)
+{
+ if (uni->custat != nstate) {
+ uni->custat = nstate;
+ uni_undel(uni, cufilt, NULL);
+ }
+}
+
+/*
+ * T309 timeout function
+ */
+static void
+t309_func(struct uni *uni)
+{
+ uni_enq_coord(uni, SIGO_T309, 0, NULL);
+}
+
+/*
+ * Respond with a status message
+ */
+void
+uni_respond_status(struct uni *uni, struct uni_cref *cref,
+ enum uni_callstate cs, enum uni_cause c1)
+{
+ struct uni_all *resp;
+
+ if ((resp = UNI_ALLOC()) == NULL)
+ return;
+
+ MK_MSG_RESP(resp, UNI_STATUS, cref);
+ MK_IE_CALLSTATE(resp->u.status.callstate, cs);
+ MK_IE_CAUSE(resp->u.status.cause, UNI_CAUSE_LOC_USER, c1);
+
+ (void)uni_send_output(resp, uni);
+
+ UNI_FREE(resp);
+}
+
+/*
+ * Respond with a status message
+ */
+void
+uni_respond_status_mtype(struct uni *uni, struct uni_cref *cref,
+ enum uni_callstate cs, enum uni_cause c1, u_int mtype)
+{
+ struct uni_all *resp;
+
+ if((resp = UNI_ALLOC()) == NULL)
+ return;
+
+ MK_MSG_RESP(resp, UNI_STATUS, cref);
+ MK_IE_CALLSTATE(resp->u.status.callstate, cs);
+ MK_IE_CAUSE(resp->u.status.cause, UNI_CAUSE_LOC_USER, c1);
+ ADD_CAUSE_MTYPE(resp->u.status.cause, mtype);
+
+ (void)uni_send_output(resp, uni);
+
+ UNI_FREE(resp);
+}
+
+/*
+ * Send a message. If we are in CUSTAT1, delay the message if we
+ * are in CUSTAT3 send it, else drop it.
+ */
+int
+uni_send_output(struct uni_all *u, struct uni *uni)
+{
+ struct uni_msg *m;
+ int err;
+
+ if (uni->custat == CU_STAT0 || uni->custat == CU_STAT2)
+ return (0);
+
+ m = uni_msg_alloc(1024);
+ if ((err = uni_encode(m, u, &uni->cx)) != 0) {
+ VERBOSE0(uni, UNI_FAC_ERR, "uni_encode failed: %08x", err);
+ uni_msg_destroy(m);
+ return (-1);
+ }
+ if (uni->custat == CU_STAT1)
+ uni_delenq_coord(uni, SIGO_DATA, 0, m);
+ else
+ uni->funcs->saal_output(uni, uni->arg, SAAL_DATA_request, m);
+ return (0);
+}
diff --git a/sys/contrib/ngatm/netnatm/sig/sig_party.c b/sys/contrib/ngatm/netnatm/sig/sig_party.c
new file mode 100644
index 0000000..c8c92b0
--- /dev/null
+++ b/sys/contrib/ngatm/netnatm/sig/sig_party.c
@@ -0,0 +1,1353 @@
+/*
+ * 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/sig/sig_party.c,v 1.12 2003/10/10 14:37:28 hbb Exp $
+ *
+ * Party instance handling
+ */
+
+#include <netnatm/unimsg.h>
+#include <netnatm/saal/sscfudef.h>
+#include <netnatm/msg/unistruct.h>
+#include <netnatm/msg/unimsglib.h>
+#include <netnatm/sig/uni.h>
+
+#include <netnatm/sig/unipriv.h>
+#include <netnatm/sig/unimkmsg.h>
+#include <netnatm/sig/unimsgcpy.h>
+
+static void drop_partyE(struct party *p);
+static int epstate_compat(struct party *, enum uni_epstate);
+
+#define DEF_PRIV_SIG(NAME, FROM) [SIG##NAME] "SIG"#NAME,
+static const char *const party_sigs[] = {
+ DEF_PARTY_SIGS
+};
+#undef DEF_PRIV_SIG
+
+TIMER_FUNC_PARTY(t397, t397_func)
+TIMER_FUNC_PARTY(t398, t398_func)
+TIMER_FUNC_PARTY(t399, t399_func)
+
+static __inline void
+set_party_state(struct party *p, enum uni_epstate state)
+{
+ if (p->state != state) {
+ VERBOSE(p->call->uni, UNI_FAC_CALL, 1,
+ "party %u/%u %u/%u PU%u -> PU%u",
+ p->call->cref, p->call->mine,
+ p->epref, p->flags & PARTY_MINE, p->state, state);
+ p->state = state;
+ }
+}
+
+/*
+ * Create a party with a given endpoint reference.
+ * No check is done, that a party with this epref does not alreay exist.
+ */
+struct party *
+uni_create_partyx(struct call *c, u_int epref, u_int mine, u_int32_t cookie)
+{
+ struct party *p;
+ struct uni_msg *api;
+ struct uniapi_party_created *ind;
+
+ mine = (mine ? PARTY_MINE : 0);
+
+ if ((p = PARTY_ALLOC()) == NULL)
+ return (NULL);
+
+ if ((ind = ALLOC_API(struct uniapi_party_created, api)) == NULL) {
+ PARTY_FREE(p);
+ return (NULL);
+ }
+
+ ind->cref.cref = c->cref;
+ ind->cref.flag = c->mine;
+ MK_IE_EPREF(ind->epref, epref, mine);
+ ind->epref.h.act = UNI_IEACT_DEFAULT;
+
+ p->call = c;
+ p->epref = epref;
+ p->flags = mine;
+ p->state = UNI_EPSTATE_NULL;;
+
+ TIMER_INIT_PARTY(p, t397);
+ TIMER_INIT_PARTY(p, t398);
+ TIMER_INIT_PARTY(p, t399);
+
+ TAILQ_INSERT_HEAD(&c->parties, p, link);
+
+ c->uni->funcs->uni_output(c->uni, c->uni->arg,
+ UNIAPI_PARTY_CREATED, cookie, api);
+
+ VERBOSE(c->uni, UNI_FAC_CALL, 1, "created party %u/%s %u/%s",
+ p->call->cref, p->call->mine ? "mine" : "his",
+ p->epref, (p->flags & PARTY_MINE) ? "mine" : "his");
+
+ return (p);
+
+}
+
+struct party *
+uni_create_party(struct call *c, struct uni_ie_epref *epref)
+{
+ return (uni_create_partyx(c, epref->epref, epref->flag, 0));
+}
+
+struct party *
+uni_find_party(struct call *c, struct uni_ie_epref *epref)
+{
+ struct party *p;
+
+ TAILQ_FOREACH(p, &c->parties, link)
+ if (p->epref == epref->epref &&
+ (!(p->flags & PARTY_MINE) == !epref->flag))
+ return (p);
+ return (NULL);
+}
+struct party *
+uni_find_partyx(struct call *c, u_int epref, u_int mine)
+{
+ struct party *p;
+
+ TAILQ_FOREACH(p, &c->parties, link)
+ if (p->epref == epref && (!(p->flags & PARTY_MINE) == !mine))
+ return (p);
+ return (NULL);
+}
+
+/*
+ * Destroy a party.
+ * This function is assumed to remove the party from the parent's call
+ * party list.
+ */
+void
+uni_destroy_party(struct party *p, int really)
+{
+ struct uni_msg *api;
+ struct uniapi_party_destroyed *ind;
+
+ TIMER_DESTROY_PARTY(p, t397);
+ TIMER_DESTROY_PARTY(p, t398);
+ TIMER_DESTROY_PARTY(p, t399);
+
+ TAILQ_REMOVE(&p->call->parties, p, link);
+
+ uni_delsig(p->call->uni, SIG_PARTY, p->call, p);
+
+ if (!really) {
+ ind = ALLOC_API(struct uniapi_party_destroyed, api);
+ if (ind != NULL) {
+ ind->cref.cref = p->call->cref;
+ ind->cref.flag = p->call->mine;
+ ind->epref.epref = p->epref;
+ ind->epref.flag = p->flags & PARTY_MINE;
+ ind->epref.h.act = UNI_IEACT_DEFAULT;
+ IE_SETPRESENT(ind->epref);
+
+ uni_enq_call(p->call, SIGC_PARTY_DESTROYED, 0, api, NULL);
+ }
+
+ uni_enq_party(p, SIGP_PARTY_DELETE, 0, NULL, NULL);
+ return;
+ }
+ PARTY_FREE(p);
+}
+
+/*
+ * Count number of parties in active states.
+ * If the argument is 0 only ACTIVE parties are counter
+ * If the argument is 1 only parties in establishing states are counted
+ * If the argument is 2 both are counted.
+ */
+u_int
+uni_party_act_count(struct call *c, int kind)
+{
+ struct party *p;
+ u_int cnt;
+
+ cnt = 0;
+ TAILQ_FOREACH(p, &c->parties, link) {
+ switch (p->state) {
+
+ case UNI_EPSTATE_ACTIVE:
+ if (kind == 0 || kind == 2)
+ cnt++;
+ break;
+
+ case UNI_EPSTATE_ALERT_RCVD:
+ case UNI_EPSTATE_ADD_INIT:
+ case UNI_EPSTATE_ALERT_DLVD:
+ case UNI_EPSTATE_ADD_RCVD:
+ if (kind == 1 || kind == 2)
+ cnt++;
+ break;
+
+ default:
+ break;
+ }
+ }
+ return (cnt);
+}
+
+static void
+stop_all_party_timers(struct party *p)
+{
+ TIMER_STOP_PARTY(p, t397);
+ TIMER_STOP_PARTY(p, t398);
+ TIMER_STOP_PARTY(p, t399);
+}
+/************************************************************/
+
+/*
+ * Add-party.request
+ *
+ * Q.2971:Party-control-U 3 (PU0)
+ * Q.2971:Party-control-N 3 (PN0)
+ */
+static void
+pun0_add_party_request(struct party *p, struct uni_msg *api, u_int32_t cookie)
+{
+ struct uni_all *add;
+ struct uniapi_add_party_request *req =
+ uni_msg_rptr(api, struct uniapi_add_party_request *);
+
+ if ((add = UNI_ALLOC()) == NULL) {
+ uni_msg_destroy(api);
+ uniapi_party_error(p, UNIAPI_ERROR_NOMEM, cookie);
+ return;
+ }
+
+ add->u.add_party = req->add;
+ MK_MSG_ORIG(add, UNI_ADD_PARTY, p->call->cref, !p->call->mine);
+ uni_send_output(add, p->call->uni);
+ UNI_FREE(add);
+
+ TIMER_START_PARTY(p, t399, p->call->uni->timer399);
+
+ set_party_state(p, UNI_EPSTATE_ADD_INIT);
+
+ uni_msg_destroy(api);
+ uniapi_party_error(p, UNIAPI_OK, cookie);
+}
+
+/*
+ * Add-party-ack.request
+ *
+ * Q.2971:Party-Control-U 6 PU2
+ * Q.2971:Party-Control-U 7 PU3
+ * Q.2971:Party-Control-N 6 PN2
+ * Q.2971:Party-Control-N 7 PN3
+ */
+static void
+punx_add_party_ack_request(struct party *p, struct uni_msg *m, u_int32_t cookie)
+{
+ struct uni_all *ack;
+ struct uniapi_add_party_ack_request *req =
+ uni_msg_rptr(m, struct uniapi_add_party_ack_request *);
+
+ if ((ack = UNI_ALLOC()) == NULL) {
+ uniapi_party_error(p, UNIAPI_ERROR_NOMEM, cookie);
+ uni_msg_destroy(m);
+ return;
+ }
+ ack->u.add_party_ack = req->ack;
+ MK_MSG_ORIG(ack, UNI_ADD_PARTY_ACK, p->call->cref, !p->call->mine);
+ uni_send_output(ack, p->call->uni);
+ UNI_FREE(ack);
+
+ set_party_state(p, UNI_EPSTATE_ACTIVE);
+
+ uni_msg_destroy(m);
+ uniapi_party_error(p, UNIAPI_OK, cookie);
+}
+
+/*
+ * Add-party-rej.request
+ *
+ * Q.2971:Party-Control-U 6 PU2
+ * Q.2971:Party-Control-N 6 PN2
+ */
+static void
+pun2_add_party_rej_request(struct party *p, struct uni_msg *m, u_int32_t cookie)
+{
+ struct uni_all *rej;
+ struct uniapi_add_party_rej_request *req =
+ uni_msg_rptr(m, struct uniapi_add_party_rej_request *);
+
+ if ((rej = UNI_ALLOC()) == NULL) {
+ uniapi_party_error(p, UNIAPI_ERROR_NOMEM, cookie);
+ uni_msg_destroy(m);
+ return;
+ }
+
+ stop_all_party_timers(p);
+
+ rej->u.add_party_rej = req->rej;
+ MK_MSG_ORIG(rej, UNI_ADD_PARTY_REJ, p->call->cref, !p->call->mine);
+ uni_enq_call(p->call, SIGC_SEND_ADD_PARTY_REJ, cookie, NULL, rej);
+
+ uni_msg_destroy(m);
+ p->state = UNI_EPSTATE_NULL;
+ uniapi_party_error(p, UNIAPI_OK, cookie);
+
+ uni_destroy_party(p, 0);
+}
+
+/*
+ * ADD PARTY in PU0, PN0
+ *
+ * Q.2971:Party-Control-U 3/14 PU0
+ */
+static void
+pun0_add_party(struct party *p, struct uni_msg *m, struct uni_all *u)
+{
+ struct uniapi_add_party_indication *ind;
+ struct uni_msg *api;
+
+ ind = ALLOC_API(struct uniapi_add_party_indication, api);
+ if (ind != NULL) {
+ ind->add.hdr = u->u.hdr;
+ copy_msg_add_party(&u->u.add_party, &ind->add);
+ p->call->uni->funcs->uni_output(p->call->uni, p->call->uni->arg,
+ UNIAPI_ADD_PARTY_indication, 0, api);
+ }
+ set_party_state(p, UNI_EPSTATE_ADD_RCVD);
+
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+}
+
+/*
+ * PARTY-ALERTING.request
+ *
+ * Q.2971:Party-Control-U 6 (PU2)
+ * Q.2971:Party-Control-N 6 (PN2)
+ */
+static void
+pun2_party_alerting_request(struct party *p, struct uni_msg *api,
+ u_int32_t cookie)
+{
+ struct uni_all *alert;
+ struct uniapi_party_alerting_request *req =
+ uni_msg_rptr(api, struct uniapi_party_alerting_request *);
+
+ if ((alert = UNI_ALLOC()) == NULL) {
+ uniapi_party_error(p, UNIAPI_ERROR_NOMEM, cookie);
+ uni_msg_destroy(api);
+ return;
+ }
+ alert->u.party_alerting = req->alert;
+ MK_MSG_ORIG(alert, UNI_PARTY_ALERTING,
+ p->call->cref, !p->call->mine);
+ uni_send_output(alert, p->call->uni);
+ UNI_FREE(alert);
+
+ set_party_state(p, UNI_EPSTATE_ALERT_DLVD);
+
+ uni_msg_destroy(api);
+ uniapi_party_error(p, UNIAPI_OK, cookie);
+}
+
+/*
+ * PARTY-ALERTING in state PU1/PN1
+ *
+ * Q.2971:Party-Control-U 14
+ * Q.2971:Party-Control-N 5
+ */
+static void
+pun1_party_alerting(struct party *p, struct uni_msg *m, struct uni_all *u)
+{
+ struct uniapi_party_alerting_indication *ind;
+ struct uni_msg *api;
+
+ ind = ALLOC_API(struct uniapi_party_alerting_indication, api);
+ if (ind == NULL) {
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+ return;
+ }
+ TIMER_STOP_PARTY(p, t399);
+
+ ind->alert.hdr = u->u.hdr;
+ copy_msg_party_alerting(&u->u.party_alerting, &ind->alert);
+
+ p->call->uni->funcs->uni_output(p->call->uni, p->call->uni->arg,
+ UNIAPI_PARTY_ALERTING_indication, 0, api);
+
+ TIMER_START_PARTY(p, t397, p->call->uni->timer397);
+
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+
+ set_party_state(p, UNI_EPSTATE_ALERT_RCVD);
+}
+
+/*
+ * ADD-PARTY-ACK
+ *
+ * Q.2971:Party-Control-U 4 (PU1)
+ * Q.2971:Party-Control-U 7 (PU4)
+ * Q.2971:Party-Control-N 4 (PN1)
+ * Q.2971:Party-Control-N 7 (PN4)
+ */
+static void
+pun1pun4_add_party_ack(struct party *p, struct uni_msg *m, struct uni_all *u)
+{
+ struct uniapi_add_party_ack_indication *ind;
+ struct uni_msg *api;
+
+ ind = ALLOC_API(struct uniapi_add_party_ack_indication, api);
+ if (ind == NULL) {
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+ return;
+ }
+
+ if (p->state == UNI_EPSTATE_ADD_INIT)
+ TIMER_STOP_PARTY(p, t399);
+ else
+ TIMER_STOP_PARTY(p, t397);
+
+ ind->ack.hdr = u->u.hdr;
+ copy_msg_add_party_ack(&u->u.add_party_ack, &ind->ack);
+
+ p->call->uni->funcs->uni_output(p->call->uni, p->call->uni->arg,
+ UNIAPI_ADD_PARTY_ACK_indication, 0, api);
+
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+
+ set_party_state(p, UNI_EPSTATE_ACTIVE);
+}
+
+/*
+ * ADD-PARTY-REJECT
+ *
+ * Q.2971:Party-Control-U 4 (PU1)
+ * Q.2971:Party-Control-N 4 (PN1)
+ */
+static void
+pun1_add_party_rej(struct party *p, struct uni_msg *m, struct uni_all *u)
+{
+ struct uniapi_add_party_rej_indication *ind;
+ struct uni_msg *api;
+
+ ind = ALLOC_API(struct uniapi_add_party_rej_indication, api);
+ if (ind == NULL) {
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+ return;
+ }
+
+ TIMER_STOP_PARTY(p, t399);
+
+ ind->rej.hdr = u->u.hdr;
+ copy_msg_add_party_rej(&u->u.add_party_rej, &ind->rej);
+ uni_enq_call(p->call, SIGC_ADD_PARTY_REJ_indication, 0, api, NULL);
+
+ uni_destroy_party(p, 0);
+
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+}
+
+/*
+ * ADD-PARTY-REJECT
+ *
+ * Q.2971:Party-Control-U 10 (PU5)
+ * Q.2971:Party-Control-N 10 (PN5)
+ */
+static void
+pun5_add_party_rej(struct party *p, struct uni_msg *m, struct uni_all *u)
+{
+ struct uniapi_drop_party_ack_indication *ind;
+ struct uni_msg *api;
+
+ ind = ALLOC_API(struct uniapi_drop_party_ack_indication, api);
+ if (ind == NULL) {
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+ return;
+ }
+
+ ind->drop.hdr = u->u.hdr;
+ COPY_FROM_ADD_REJ(u, &ind->drop);
+ if (IE_ISGOOD(u->u.add_party_rej.crankback))
+ ind->crankback = u->u.add_party_rej.crankback;
+ uni_enq_call(p->call, SIGC_DROP_PARTY_ACK_indication, 0, api, NULL);
+
+ TIMER_STOP_PARTY(p, t398);
+
+ uni_destroy_party(p, 0);
+
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+}
+
+/*
+ * DROP-PARTY-ACKNOWLEDGE
+ *
+ * Q.2971:Party-Control-U 8
+ * Q.2971:Party-Control-N 8
+ *
+ * Message already verified in Call-Control!
+ */
+static void
+punx_drop_party_ack(struct party *p, struct uni_msg *m, struct uni_all *u)
+{
+ struct uniapi_drop_party_ack_indication *ind;
+ struct uni_msg *api;
+
+ stop_all_party_timers(p);
+
+ ind = ALLOC_API(struct uniapi_drop_party_ack_indication, api);
+ if (ind != NULL) {
+ ind->drop.hdr = u->u.hdr;
+ COPY_FROM_DROP_ACK(u, &ind->drop);
+ uni_enq_call(p->call, SIGC_DROP_PARTY_ACK_indication,
+ 0, api, NULL);
+ }
+
+ uni_destroy_party(p, 0);
+
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+}
+
+/*
+ * DROP PARTY message in any state except PU5/PN5
+ *
+ * Q.2971:Party-Control-U 9
+ * Q.2971:Party-Control-N 9
+ */
+static void
+punx_drop_party(struct party *p, struct uni_msg *m, struct uni_all *u)
+{
+ struct uniapi_drop_party_indication *ind;
+ struct uni_msg *api;
+
+ ind = ALLOC_API(struct uniapi_drop_party_indication, api);
+ if (ind == NULL) {
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+ return;
+ }
+
+ ind->drop.hdr = u->u.hdr;
+ copy_msg_drop_party(&u->u.drop_party, &ind->drop);
+
+ /* need the cause even if it is bad */
+ if (IE_ISERROR(u->u.drop_party.cause))
+ ind->drop.cause = u->u.drop_party.cause;
+
+ ind->my_cause = p->call->uni->cause;
+
+ uni_enq_call(p->call, SIGC_DROP_PARTY_indication, 0, api, NULL);
+
+ TIMER_STOP_PARTY(p, t397);
+ TIMER_STOP_PARTY(p, t399);
+
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+
+ set_party_state(p, UNI_EPSTATE_DROP_RCVD);
+}
+
+/*
+ * DROP PARTY message in state PU5/PN5
+ *
+ * Q.2971:Party-Control-U 10
+ * Q.2971:Party-Control-N 10
+ */
+static void
+pun5_drop_party(struct party *p, struct uni_msg *m, struct uni_all *u)
+{
+ struct uniapi_drop_party_ack_indication *ind;
+ struct uni_msg *api;
+
+ ind = ALLOC_API(struct uniapi_drop_party_ack_indication, api);
+ if (ind == NULL) {
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+ return;
+ }
+
+ ind->drop.hdr = u->u.hdr;
+ copy_msg_drop_party(&u->u.drop_party, &ind->drop);
+
+ /* need the cause even if it is bad */
+ if (IE_ISERROR(u->u.drop_party.cause))
+ ind->drop.cause = u->u.drop_party.cause;
+
+ uni_enq_call(p->call, SIGC_DROP_PARTY_ACK_indication, 0, api, NULL);
+
+ TIMER_STOP_PARTY(p, t398);
+
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+
+ set_party_state(p, UNI_EPSTATE_DROP_RCVD);
+
+ uni_destroy_party(p, 0);
+}
+
+/************************************************************/
+
+/*
+ * T399
+ *
+ * Q.2971:Party-Control-U 4 (PU1)
+ * Q.2971:Party-Control-N 4 (PN1)
+ */
+static void
+pun1_t399(struct party *p)
+{
+ if (p->call->uni->proto == UNIPROTO_UNI40N) {
+ MK_IE_CAUSE(p->call->uni->cause, UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_NO_RESPONSE);
+ } else {
+ MK_IE_CAUSE(p->call->uni->cause, UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_RECOVER);
+ ADD_CAUSE_TIMER(p->call->uni->cause, "399");
+ }
+
+ drop_partyE(p);
+}
+
+/*
+ * T398
+ *
+ * Q.2971:Party-Control-U 10 (PU5)
+ * Q.2971:Party-Control-N 10 (PN5)
+ */
+static void
+pun5_t398(struct party *p)
+{
+ struct uniapi_drop_party_ack_indication *ind;
+ struct uni_all *drop;
+ struct uni_msg *api;
+
+ MK_IE_CAUSE(p->call->uni->cause,
+ UNI_CAUSE_LOC_USER, UNI_CAUSE_RECOVER);
+ ADD_CAUSE_TIMER(p->call->uni->cause, "398");
+ /*
+ * Send indication to API
+ */
+ ind = ALLOC_API(struct uniapi_drop_party_ack_indication, api);
+ if (ind != NULL) {
+ ind->drop.hdr.cref.cref = p->call->cref;
+ ind->drop.hdr.cref.flag = p->call->mine;
+ ind->drop.hdr.act = UNI_MSGACT_DEFAULT;
+ MK_IE_EPREF(ind->drop.epref, p->epref, p->flags & PARTY_MINE);
+ ind->drop.cause = p->call->uni->cause;
+ uni_enq_call(p->call, SIGC_DROP_PARTY_ACK_indication,
+ 0, api, NULL);
+ }
+
+ /*
+ * Send DROP PARTY ACK
+ */
+ if ((drop = UNI_ALLOC()) != NULL) {
+ MK_MSG_ORIG(drop, UNI_DROP_PARTY_ACK,
+ p->call->cref, !p->call->mine);
+ MK_IE_EPREF(drop->u.drop_party_ack.epref,
+ p->epref, !(p->flags & PARTY_MINE));
+ drop->u.drop_party_ack.cause = p->call->uni->cause;
+ uni_enq_call(p->call, SIGC_SEND_DROP_PARTY_ACK, 0, NULL, drop);
+ }
+
+ uni_destroy_party(p, 0);
+}
+
+/*
+ * T397
+ *
+ * Q.2971:Party-Control-U 7 (PU4)
+ * Q.2971:Party-Control-N 7 (PN4)
+ */
+static void
+pun4_t397(struct party *p)
+{
+ MK_IE_CAUSE(p->call->uni->cause, UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_RECOVER);
+ ADD_CAUSE_TIMER(p->call->uni->cause, "397");
+
+ drop_partyE(p);
+}
+
+/************************************************************/
+
+/*
+ * Drop a party because of an error condition.
+ * This is label E on page Party-Control-U 8/14.
+ *
+ * It is assumed, that the caller has constructed the cause in
+ * p->call->uni->cause.
+ */
+static void
+drop_partyE(struct party *p)
+{
+ struct uni_msg *api;
+ struct uniapi_drop_party_indication *ind;
+ struct uni_all *drop;
+
+ /*
+ * Send indication to API
+ */
+ if ((ind = ALLOC_API(struct uniapi_drop_party_indication, api)) != NULL) {
+ ind->drop.hdr.cref.cref = p->call->cref;
+ ind->drop.hdr.cref.flag = p->call->mine;
+ ind->drop.hdr.act = UNI_MSGACT_DEFAULT;
+ MK_IE_EPREF(ind->drop.epref, p->epref, p->flags & PARTY_MINE);
+ ind->drop.cause = p->call->uni->cause;
+ uni_enq_call(p->call, SIGC_DROP_PARTY_indication, 0, api, NULL);
+ }
+ TIMER_STOP_PARTY(p, t399);
+ TIMER_STOP_PARTY(p, t397);
+ TIMER_START_PARTY(p, t398, p->call->uni->timer398);
+
+ if ((drop = UNI_ALLOC()) != NULL) {
+ drop->u.drop_party.cause = p->call->uni->cause;
+ MK_MSG_ORIG(drop, UNI_DROP_PARTY, p->call->cref, !p->call->mine);
+ MK_IE_EPREF(drop->u.drop_party.epref, p->epref,
+ !(p->flags & PARTY_MINE));
+ uni_enq_call(p->call, SIGC_SEND_DROP_PARTY, 0, NULL, drop);
+ }
+
+ set_party_state(p, UNI_EPSTATE_DROP_INIT);
+}
+
+/*
+ * Drop party request in Px1, Px3, Px4 or Px7
+ *
+ * Q.2971:Party-Control-U 8
+ * Q.2971:Party-Control-N 8
+ */
+static void
+punx_drop_party_request(struct party *p, struct uni_msg *api, u_int32_t cookie)
+{
+ struct uniapi_drop_party_request *req =
+ uni_msg_rptr(api, struct uniapi_drop_party_request *);
+ struct uni_all *drop;
+
+ if ((drop = UNI_ALLOC()) == NULL) {
+ uniapi_party_error(p, UNIAPI_ERROR_NOMEM, cookie);
+ uni_msg_destroy(api);
+ return;
+ }
+
+ TIMER_STOP_PARTY(p, t399);
+ TIMER_STOP_PARTY(p, t397);
+ TIMER_START_PARTY(p, t398, p->call->uni->timer398);
+
+ drop->u.drop_party = req->drop;
+ MK_MSG_ORIG(drop, UNI_DROP_PARTY, p->call->cref, !p->call->mine);
+ uni_enq_call(p->call, SIGC_SEND_DROP_PARTY, cookie, NULL, drop);
+
+ set_party_state(p, UNI_EPSTATE_DROP_INIT);
+
+ uni_msg_destroy(api);
+ uniapi_party_error(p, UNIAPI_OK, cookie);
+}
+
+/*
+ * Drop-party-ack.request in Px6
+ *
+ * Q.2971:Party-Control-U 9
+ * Q.2971:Party-Control-N 9
+ */
+static void
+pun6_drop_party_ack_request(struct party *p, struct uni_msg *api, u_int32_t cookie)
+{
+ struct uniapi_drop_party_ack_request *req =
+ uni_msg_rptr(api, struct uniapi_drop_party_ack_request *);
+ struct uni_all *ack;
+
+ if ((ack = UNI_ALLOC()) == NULL) {
+ uni_msg_destroy(api);
+ uniapi_party_error(p, UNIAPI_ERROR_NOMEM, cookie);
+ return;
+ }
+ ack->u.drop_party_ack = req->ack;
+ MK_MSG_ORIG(ack, UNI_DROP_PARTY_ACK, p->call->cref, !p->call->mine);
+ uni_enq_call(p->call, SIGC_SEND_DROP_PARTY_ACK, cookie, NULL, ack);
+
+ stop_all_party_timers(p);
+
+ uni_msg_destroy(api);
+ uniapi_party_error(p, UNIAPI_OK, cookie);
+
+ uni_destroy_party(p, 0);
+}
+/************************************************************/
+/*
+ * Party status enquiry request from API or call-control
+ *
+ * Q.2971:Party-Control-U 12
+ * Q.2971:Party-Control-N 12
+ */
+static void
+punx_status_enquiry_request(struct party *p, u_int32_t cookie)
+{
+ struct uni_all *enq;
+
+ if((enq = UNI_ALLOC()) == NULL) {
+ uniapi_party_error(p, UNIAPI_ERROR_NOMEM, cookie);
+ return;
+ }
+ MK_IE_EPREF(enq->u.status_enq.epref, p->epref,
+ !(p->flags & PARTY_MINE));
+ MK_MSG_ORIG(enq, UNI_STATUS_ENQ, p->call->cref, !p->call->mine);
+ uni_enq_call(p->call, SIGC_SEND_STATUS_ENQ, cookie, NULL, enq);
+
+ uniapi_party_error(p, UNIAPI_OK, cookie);
+}
+
+/*
+ * STATUS in any state except PU5/PN5
+ *
+ * Q.2971:Party-Control-U 12
+ * Q.2971:Party-Control-N 12
+ */
+static void
+punx_status(struct party *p, struct uni_msg *m, struct uni_all *u)
+{
+ struct uniapi_drop_party_ack_indication *ind;
+ struct uni_msg *api;
+
+ if (u->u.status.epstate.state == UNI_EPSTATE_NULL) {
+ /* should not happend */
+ ind = ALLOC_API(struct uniapi_drop_party_ack_indication, api);
+ if (ind != NULL) {
+ ind->drop.hdr = u->u.hdr;
+ ind->drop.cause = u->u.status.cause;
+ ind->drop.epref = u->u.status.epref;
+ uni_enq_call(p->call, SIGC_DROP_PARTY_ACK_indication,
+ 0, api, NULL);
+ }
+ stop_all_party_timers(p);
+
+ uni_destroy_party(p, 0);
+ } else {
+ if (epstate_compat(p, u->u.status.epstate.state)) {
+ if(u->u.status.cause.cause == UNI_CAUSE_MANDAT ||
+ u->u.status.cause.cause == UNI_CAUSE_MTYPE_NIMPL ||
+ u->u.status.cause.cause == UNI_CAUSE_IE_NIMPL ||
+ u->u.status.cause.cause == UNI_CAUSE_IE_INV) {
+ MK_IE_CAUSE(p->call->uni->cause,
+ UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_UNSPEC);
+ drop_partyE(p);
+ }
+ } else {
+ MK_IE_CAUSE(p->call->uni->cause,
+ UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_MSG_INCOMP);
+ drop_partyE(p);
+ }
+ }
+
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+}
+
+/*
+ * STATUS in PU5/PN5
+ *
+ * Q.2971:Party-Control-U 10
+ * Q.2971:Party-Control-N 10
+ */
+static void
+pun5_status(struct party *p, struct uni_msg *m, struct uni_all *u)
+{
+ struct uniapi_drop_party_ack_indication *ind;
+ struct uni_msg *api;
+
+ if (u->u.status.epstate.state == UNI_EPSTATE_NULL) {
+ ind = ALLOC_API(struct uniapi_drop_party_ack_indication, api);
+ if (ind != NULL) {
+ ind->drop.hdr = u->u.hdr;
+ ind->drop.cause = u->u.status.cause;
+ ind->drop.epref = u->u.status.epref;
+ uni_enq_call(p->call, SIGC_DROP_PARTY_ACK_indication,
+ 0, api, NULL);
+ }
+ TIMER_STOP_PARTY(p, t398);
+
+ uni_destroy_party(p, 0);
+ }
+
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+}
+
+/************************************************************/
+
+void
+uni_sig_party(struct party *p, enum party_sig sig, u_int32_t cookie,
+ struct uni_msg *msg, struct uni_all *u)
+{
+ if (sig >= SIGP_END) {
+ VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
+ "Signal %d outside of range to Party-Control", sig);
+ if (msg)
+ uni_msg_destroy(msg);
+ if (u)
+ UNI_FREE(u);
+ return;
+ }
+ VERBOSE(p->call->uni, UNI_FAC_CALL, 1,
+ "Signal %s in state %u of party %u/%s (call %u/%s in state %s)"
+ "; cookie %u", party_sigs[sig], p->state, p->epref,
+ (p->flags & PARTY_MINE) ? "mine" : "his", p->call->cref,
+ p->call->mine ? "mine" : "his", callstates[p->call->cstate].name,
+ cookie);
+
+ switch (sig) {
+
+ case SIGP_PARTY_DELETE:
+ PARTY_FREE(p);
+ break;
+
+ /*
+ * Messages
+ */
+ case SIGP_SETUP:
+ if (p->state == UNI_EPSTATE_NULL) {
+ /* Q.2971:Call-Control-U 3/13 */
+ /* Q.2971:Call-Control-N 3/13 */
+ set_party_state(p, UNI_EPSTATE_ADD_RCVD);
+ break;
+ }
+ VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
+ "SETUP in ps=%u", p->state);
+ break;
+
+ case SIGP_ALERTING:
+ if (p->state == UNI_EPSTATE_ADD_INIT) {
+ /* Q.2971:Call-Control-U 14 */
+ /* Q.2971:Call-Control-N 5 */
+ TIMER_START_PARTY(p, t397, p->call->uni->timer397);
+ set_party_state(p, UNI_EPSTATE_ALERT_RCVD);
+ break;
+ }
+ VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
+ "ALERTING in ps=%u", p->state);
+ break;
+
+ case SIGP_CONNECT:
+ if (p->state == UNI_EPSTATE_ADD_INIT) {
+ /* Q.2971:Call-Control-U 4/13 */
+ TIMER_STOP_PARTY(p, t399);
+ set_party_state(p, UNI_EPSTATE_ACTIVE);
+ break;
+ }
+ if (p->state == UNI_EPSTATE_ALERT_RCVD) {
+ /* Q.2971:Call-Control-U 7/13 */
+ TIMER_STOP_PARTY(p, t397);
+ set_party_state(p, UNI_EPSTATE_ACTIVE);
+ break;
+ }
+ VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
+ "CONNECT in ps=%u", p->state);
+ break;
+
+ case SIGP_CONNECT_ACK:
+ if (p->state == UNI_EPSTATE_ADD_RCVD ||
+ p->state == UNI_EPSTATE_ALERT_DLVD) {
+ /* Q.2971:Call-Control-U 6/13 */
+ /* Q.2971:Call-Control-U 7/13 */
+ p->flags &= ~PARTY_CONNECT;
+ set_party_state(p, UNI_EPSTATE_ACTIVE);
+ break;
+ }
+ VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
+ "CONNECT in ps=%u", p->state);
+ break;
+
+ case SIGP_RELEASE:
+ if (p->state == UNI_EPSTATE_DROP_INIT) {
+ /* Q.2971:Party-Control-U 10/14 */
+ /* Q.2971:Party-Control-N 10/14 */
+ TIMER_STOP_PARTY(p, t398);
+ uni_destroy_party(p, 0);
+ break;
+ }
+ /* Q.2971:Party-Control-U 11/14 */
+ /* Q.2971:Party-Control-N 11/14 */
+ TIMER_STOP_PARTY(p, t397);
+ TIMER_STOP_PARTY(p, t399);
+ uni_destroy_party(p, 0);
+ break;
+
+ case SIGP_RELEASE_COMPL:
+ /* Q.2971:Party-Control-U 11/14 */
+ /* Q.2971:Party-Control-N 11/14 */
+ stop_all_party_timers(p);
+ uni_destroy_party(p, 0);
+ break;
+
+ case SIGP_RELEASE_confirm:
+ /* not in the SDLs */
+ stop_all_party_timers(p);
+ uni_destroy_party(p, 0);
+ break;
+
+ case SIGP_RELEASE_request:
+ if (p->state == UNI_EPSTATE_DROP_INIT) {
+ /* Q.2971:Party-Control-U 10 */
+ /* Q.2971:Party-Control-N 10 */
+ uni_destroy_party(p, 0);
+ break;
+ }
+ /* Q.2971:Party-Control-U 11 */
+ /* Q.2971:Party-Control-N 11 */
+ TIMER_STOP_PARTY(p, t397);
+ TIMER_STOP_PARTY(p, t399);
+ uni_destroy_party(p, 0);
+ break;
+
+ case SIGP_RELEASE_response:
+ /* Q.2971:Party-Control-U 11 */
+ /* Q.2971:Party-Control-N 11 */
+ stop_all_party_timers(p);
+ uni_destroy_party(p, 0);
+ break;
+
+ case SIGP_ADD_PARTY:
+ if (p->state == UNI_EPSTATE_NULL) {
+ /* Q.2971:Party-Control-U 3 PU0 */
+ /* Q.2971:Party-Control-N 3 PN0 */
+ pun0_add_party(p, msg, u);
+ break;
+ }
+ if (p->state == UNI_EPSTATE_ADD_RCVD) {
+ /* Q.2971:Party-Control-U 6 PU2 */
+ /* Q.2971:Party-Control-N 6 PN2 */
+ uni_msg_destroy(msg);
+ UNI_FREE(u);
+ break;
+ }
+ uni_bad_message(p->call, u, UNI_CAUSE_MSG_INCOMP,
+ &u->u.add_party.epref, p->state);
+ uni_msg_destroy(msg);
+ UNI_FREE(u);
+ break;
+
+ case SIGP_PARTY_ALERTING:
+ if (p->state == UNI_EPSTATE_ADD_INIT) {
+ /* Q.2971:Party-Control-U 14 */
+ /* Q.2971:Party-Control-N 5 */
+ pun1_party_alerting(p, msg, u);
+ break;
+ }
+ uni_bad_message(p->call, u, UNI_CAUSE_MSG_INCOMP,
+ &u->u.party_alerting.epref, p->state);
+ uni_msg_destroy(msg);
+ UNI_FREE(u);
+ break;
+
+ case SIGP_ADD_PARTY_ACK:
+ if (p->state == UNI_EPSTATE_ADD_INIT ||
+ p->state == UNI_EPSTATE_ALERT_RCVD) {
+ /* Q.2971:Party-Control-U 4 (PU1) */
+ /* Q.2971:Party-Control-U 7 (PU4) */
+ /* Q.2971:Party-Control-N 4 (PN1) */
+ /* Q.2971:Party-Control-N 7 (PN4) */
+ pun1pun4_add_party_ack(p, msg, u);
+ break;
+ }
+ uni_bad_message(p->call, u, UNI_CAUSE_MSG_INCOMP,
+ &u->u.add_party_ack.epref, p->state);
+ uni_msg_destroy(msg);
+ UNI_FREE(u);
+ break;
+
+ case SIGP_ADD_PARTY_REJ:
+ if (p->state == UNI_EPSTATE_ADD_INIT) {
+ /* Q.2971:Party-Control-U 4 (PU1) */
+ /* Q.2971:Party-Control-N 4 (PN1) */
+ pun1_add_party_rej(p, msg, u);
+ break;
+ }
+ if (p->state == UNI_EPSTATE_DROP_INIT) {
+ /* Q.2971:Party-Control-U 10 (PU5) */
+ /* Q.2971:Party-Control-N 10 (PN5) */
+ pun5_add_party_rej(p, msg, u);
+ break;
+ }
+ uni_bad_message(p->call, u, UNI_CAUSE_MSG_INCOMP,
+ &u->u.add_party_rej.epref, p->state);
+ uni_msg_destroy(msg);
+ UNI_FREE(u);
+ break;
+
+ case SIGP_DROP_PARTY_ACK:
+ /* Q.2971:Party-Control-U 8 */
+ /* Q.2971:Party-Control-N 8 */
+ punx_drop_party_ack(p, msg, u);
+ break;
+
+ case SIGP_DROP_PARTY:
+ if (p->state == UNI_EPSTATE_DROP_INIT)
+ /* Q.2971:Party-Control-U 10 */
+ /* Q.2971:Party-Control-N 10 */
+ pun5_drop_party(p, msg, u);
+ else
+ /* Q.2971:Party-Control-U 9 */
+ /* Q.2971:Party-Control-N 9 */
+ punx_drop_party(p, msg, u);
+ break;
+
+ case SIGP_STATUS:
+ if (p->state == UNI_EPSTATE_DROP_INIT)
+ /* Q.2971:Party-Control-U 10 */
+ /* Q.2971:Party-Control-N 10 */
+ pun5_status(p, msg, u);
+ else
+ /* Q.2971:Party-Control-U 12 */
+ /* Q.2971:Party-Control-N 12 */
+ punx_status(p, msg, u);
+ break;
+
+ /*
+ * User
+ */
+ case SIGP_SETUP_request:
+ if (p->state == UNI_EPSTATE_NULL) {
+ /* Q.2971:Party-Control-U 3 */
+ /* Q.2971:Party-Control-N 3 */
+ set_party_state(p, UNI_EPSTATE_ADD_INIT);
+ break;
+ }
+ VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
+ "SETUP.request in ps=%u", p->state);
+ uniapi_party_error(p, UNIAPI_ERROR_BAD_EPSTATE, cookie);
+ break;
+
+ case SIGP_SETUP_response:
+ if (p->state == UNI_EPSTATE_ADD_RCVD ||
+ p->state == UNI_EPSTATE_ALERT_DLVD) {
+ /* Q.2971:Party-Control-N 6 (PN2) */
+ /* Q.2971:Party-Control-N 7 (PN3) */
+ set_party_state(p, UNI_EPSTATE_ACTIVE);
+ break;
+ }
+ VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
+ "SETUP.response in ps=%u", p->state);
+ uniapi_party_error(p, UNIAPI_ERROR_BAD_EPSTATE, cookie);
+ break;
+
+ case SIGP_SETUP_COMPL_request:
+ if (p->state == UNI_EPSTATE_ADD_INIT) {
+ /* Q.2971:Party-Control-N 4 */
+ TIMER_STOP_PARTY(p, t399);
+ set_party_state(p, UNI_EPSTATE_ACTIVE);
+ break;
+ }
+ if (p->state == UNI_EPSTATE_ALERT_RCVD) {
+ /* Q.2971:Party-Control-N 7 */
+ TIMER_STOP_PARTY(p, t397);
+ set_party_state(p, UNI_EPSTATE_ACTIVE);
+ break;
+ }
+ VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
+ "SETUP_COMPL.request in ps=%u", p->state);
+ uniapi_party_error(p, UNIAPI_ERROR_BAD_EPSTATE, cookie);
+ break;
+
+ case SIGP_ADD_PARTY_request:
+ if (p->state == UNI_EPSTATE_NULL) {
+ /* Q.2971:Party-control-U 3 (PU0) */
+ /* Q.2971:Party-control-N 3 (PN0) */
+ pun0_add_party_request(p, msg, cookie);
+ break;
+ }
+ VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
+ "Add-party.request in ps=%u", p->state);
+ uniapi_party_error(p, UNIAPI_ERROR_BAD_EPSTATE, cookie);
+ uni_msg_destroy(msg);
+ break;
+
+ case SIGP_ALERTING_request:
+ /* Q.2971:Party-Control-U 6 (PU2) */
+ /* Q.2971:Party-Control-N 6 (PN2) */
+ set_party_state(p, UNI_EPSTATE_ALERT_DLVD);
+ break;
+
+ case SIGP_PARTY_ALERTING_request:
+ if (p->state == UNI_EPSTATE_ADD_RCVD) {
+ /* Q.2971:Party-Control-U 6 (PU2) */
+ /* Q.2971:Party-Control-N 6 (PN2) */
+ pun2_party_alerting_request(p, msg, cookie);
+ break;
+ }
+ VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
+ "Party-alerting.request in ps=%u", p->state);
+ uniapi_party_error(p, UNIAPI_ERROR_BAD_EPSTATE, cookie);
+ uni_msg_destroy(msg);
+ break;
+
+ case SIGP_ADD_PARTY_ACK_request:
+ if (p->state == UNI_EPSTATE_ADD_RCVD ||
+ p->state == UNI_EPSTATE_ALERT_DLVD) {
+ /* Q.2971:Party-Control-U 6 PU2 */
+ /* Q.2971:Party-Control-U 7 PU3 */
+ /* Q.2971:Party-Control-N 6 PN2 */
+ /* Q.2971:Party-Control-N 7 PN3 */
+ punx_add_party_ack_request(p, msg, cookie);
+ break;
+ }
+ VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
+ "Add-party-ack.request in ps=%u", p->state);
+ uniapi_party_error(p, UNIAPI_ERROR_BAD_EPSTATE, cookie);
+ uni_msg_destroy(msg);
+ break;
+
+ case SIGP_ADD_PARTY_REJ_request:
+ if (p->state == UNI_EPSTATE_ADD_RCVD) {
+ /* Q.2971:Party-Control-U 6 PU2 */
+ /* Q.2971:Party-Control-N 6 PN2 */
+ pun2_add_party_rej_request(p, msg, cookie);
+ break;
+ }
+ VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
+ "Add-party-rej.request in ps=%u", p->state);
+ uniapi_party_error(p, UNIAPI_ERROR_BAD_EPSTATE, cookie);
+ uni_msg_destroy(msg);
+ break;
+
+ case SIGP_DROP_PARTY_request:
+ if (p->state == UNI_EPSTATE_ADD_INIT ||
+ p->state == UNI_EPSTATE_ALERT_DLVD ||
+ p->state == UNI_EPSTATE_ALERT_RCVD ||
+ p->state == UNI_EPSTATE_ACTIVE) {
+ /* Q.2971:Party-Control-U 8 */
+ /* Q.2971:Party-Control-N 8 */
+ punx_drop_party_request(p, msg, cookie);
+ break;
+ }
+ VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
+ "Drop-party.request in ps=%u", p->state);
+ uniapi_party_error(p, UNIAPI_ERROR_BAD_EPSTATE, cookie);
+ uni_msg_destroy(msg);
+ break;
+
+ case SIGP_DROP_PARTY_ACK_request:
+ if (p->state == UNI_EPSTATE_DROP_RCVD) {
+ /* Q.2971:Party-Control-U 9 */
+ /* Q.2971:Party-Control-N 9 */
+ pun6_drop_party_ack_request(p, msg, cookie);
+ break;
+ }
+ VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
+ "Drop-party-ack.request in ps=%u", p->state);
+ uniapi_party_error(p, UNIAPI_ERROR_BAD_EPSTATE, cookie);
+ uni_msg_destroy(msg);
+ break;
+
+ case SIGP_STATUS_ENQUIRY_request:
+ /* Q.2971:Party-Control-U 12 */
+ /* Q.2971:Party-Control-N 12 */
+ punx_status_enquiry_request(p, cookie);
+ break;
+
+ /*
+ * Timers
+ */
+ case SIGP_T397:
+ if (p->state == UNI_EPSTATE_ALERT_RCVD) {
+ /* Q.2971:Party-Control-U 7 (PU4) */
+ /* Q.2971:Party-Control-N 7 (PN4) */
+ pun4_t397(p);
+ break;
+ }
+ VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
+ "T397 in ps=%u", p->state);
+ break;
+
+ case SIGP_T398:
+ if (p->state == UNI_EPSTATE_DROP_INIT) {
+ /* Q.2971:Party-Control-U 10 (PU5) */
+ /* Q.2971:Party-Control-N 10 (PN5) */
+ pun5_t398(p);
+ break;
+ }
+ VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
+ "T398 in ps=%u", p->state);
+ break;
+
+ case SIGP_T399:
+ if (p->state == UNI_EPSTATE_ADD_INIT) {
+ /* Q.2971:Party-Control-U 4 (PU1) */
+ /* Q.2971:Party-Control-N 4 (PN1) */
+ pun1_t399(p);
+ break;
+ }
+ VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
+ "T399 in ps=%u", p->state);
+ break;
+
+ case SIGP_END:
+ break;
+ }
+}
+
+static void
+t397_func(struct party *p)
+{
+ uni_enq_party(p, SIGP_T397, 0, NULL, NULL);
+}
+static void
+t398_func(struct party *p)
+{
+ uni_enq_party(p, SIGP_T398, 0, NULL, NULL);
+}
+static void
+t399_func(struct party *p)
+{
+ uni_enq_party(p, SIGP_T399, 0, NULL, NULL);
+}
+
+static int
+epstate_compat(struct party *p, enum uni_epstate state)
+{
+ if (p->state == UNI_EPSTATE_ADD_INIT ||
+ p->state == UNI_EPSTATE_ALERT_RCVD)
+ if (state == UNI_EPSTATE_ADD_INIT ||
+ state == UNI_EPSTATE_ALERT_RCVD)
+ return (0);
+ if (p->state == UNI_EPSTATE_ADD_RCVD ||
+ p->state == UNI_EPSTATE_ALERT_DLVD)
+ if (state == UNI_EPSTATE_ADD_RCVD ||
+ state == UNI_EPSTATE_ALERT_DLVD)
+ return (0);
+ return (1);
+}
diff --git a/sys/contrib/ngatm/netnatm/sig/sig_print.c b/sys/contrib/ngatm/netnatm/sig/sig_print.c
new file mode 100644
index 0000000..56bb9ce
--- /dev/null
+++ b/sys/contrib/ngatm/netnatm/sig/sig_print.c
@@ -0,0 +1,622 @@
+/*
+ * Copyright (c) 2002-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>
+ * Kendy Kutzner <kutzner@fokus.fraunhofer.de>
+ *
+ * $Begemot: libunimsg/atm/sig/sig_print.c,v 1.4 2003/09/19 12:03:34 hbb Exp $
+ */
+
+#include <sys/types.h>
+#ifdef _KERNEL
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/libkern.h>
+#include <machine/stdarg.h>
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#endif
+
+#include <netnatm/saal/sscfu.h>
+#include <netnatm/msg/uni_hdr.h>
+#include <netnatm/msg/unistruct.h>
+#include <netnatm/msg/unimsglib.h>
+#include <netnatm/msg/uniprint.h>
+#include <netnatm/sig/uni.h>
+#include <netnatm/sig/unisig.h>
+#include <netnatm/sig/unidef.h>
+
+const char *
+uni_strerr(u_int err)
+{
+ static const char *const errstr[] = {
+#define DEF(NAME, VAL, STR) [UNIAPI_##NAME] STR,
+UNIAPI_DEF_ERRORS(DEF)
+#undef DEF
+ };
+ static char buf[100];
+
+ if (err >= sizeof(errstr)/sizeof(errstr[0]) || errstr[err] == NULL) {
+ sprintf(buf, "Unknown error %u", err);
+ return (buf);
+ }
+ return (errstr[err]);
+}
+
+#define D(M) [M] #M
+static const char *const msgs[] = {
+ D(UNIAPI_ERROR),
+ D(UNIAPI_CALL_CREATED),
+ D(UNIAPI_CALL_DESTROYED),
+ D(UNIAPI_PARTY_CREATED),
+ D(UNIAPI_PARTY_DESTROYED),
+ D(UNIAPI_LINK_ESTABLISH_request),
+ D(UNIAPI_LINK_ESTABLISH_confirm),
+ D(UNIAPI_LINK_RELEASE_request),
+ D(UNIAPI_LINK_RELEASE_confirm),
+ D(UNIAPI_RESET_request),
+ D(UNIAPI_RESET_confirm),
+ D(UNIAPI_RESET_indication),
+ D(UNIAPI_RESET_ERROR_indication),
+ D(UNIAPI_RESET_response),
+ D(UNIAPI_RESET_ERROR_response),
+ D(UNIAPI_RESET_STATUS_indication),
+ D(UNIAPI_SETUP_request),
+ D(UNIAPI_SETUP_indication),
+ D(UNIAPI_SETUP_response),
+ D(UNIAPI_SETUP_confirm),
+ D(UNIAPI_SETUP_COMPLETE_indication),
+ D(UNIAPI_SETUP_COMPLETE_request),
+ D(UNIAPI_ALERTING_request),
+ D(UNIAPI_ALERTING_indication),
+ D(UNIAPI_PROCEEDING_request),
+ D(UNIAPI_PROCEEDING_indication),
+ D(UNIAPI_RELEASE_request),
+ D(UNIAPI_RELEASE_indication),
+ D(UNIAPI_RELEASE_response),
+ D(UNIAPI_RELEASE_confirm),
+ D(UNIAPI_NOTIFY_request),
+ D(UNIAPI_NOTIFY_indication),
+ D(UNIAPI_STATUS_indication),
+ D(UNIAPI_STATUS_ENQUIRY_request),
+ D(UNIAPI_ADD_PARTY_request),
+ D(UNIAPI_ADD_PARTY_indication),
+ D(UNIAPI_PARTY_ALERTING_request),
+ D(UNIAPI_PARTY_ALERTING_indication),
+ D(UNIAPI_ADD_PARTY_ACK_request),
+ D(UNIAPI_ADD_PARTY_ACK_indication),
+ D(UNIAPI_ADD_PARTY_REJ_request),
+ D(UNIAPI_ADD_PARTY_REJ_indication),
+ D(UNIAPI_DROP_PARTY_request),
+ D(UNIAPI_DROP_PARTY_indication),
+ D(UNIAPI_DROP_PARTY_ACK_request),
+ D(UNIAPI_DROP_PARTY_ACK_indication),
+ D(UNIAPI_ABORT_CALL_request),
+};
+#undef D
+
+void
+uni_print_api(char *buf, size_t bufsiz, u_int type, u_int cookie,
+ const void *msg, struct unicx *cx)
+{
+ int old_dont_init = cx->dont_init;
+
+ uni_print_init(buf, bufsiz, cx);
+ cx->dont_init = 1;
+
+ if (type >= sizeof(msgs) / sizeof(msgs[0]) || msgs[type] == NULL) {
+ uni_print_flag("UNIAPI_UNKNOWN", cx);
+ uni_print_entry(cx, "sig", "%u", type);
+ uni_print_entry(cx, "cookie", "%u", cookie);
+ goto out;
+ }
+
+ uni_print_flag(msgs[type], cx);
+ uni_print_entry(cx, "cookie", "%u", cookie);
+ cx->indent++;
+
+ switch (type) {
+
+ case UNIAPI_ERROR:
+ {
+ const struct uniapi_error *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_entry(cx, "reason", "%s", uni_strerr(api->reason));
+ uni_print_entry(cx, "state", "U%u", api->state);
+ break;
+ }
+
+ case UNIAPI_CALL_CREATED:
+ {
+ const struct uniapi_call_created *api = msg;
+
+ uni_print_cref(NULL, 0, &api->cref, cx);
+ break;
+ }
+
+ case UNIAPI_CALL_DESTROYED:
+ {
+ const struct uniapi_call_destroyed *api = msg;
+
+ uni_print_cref(NULL, 0, &api->cref, cx);
+ break;
+ }
+
+ case UNIAPI_PARTY_CREATED:
+ {
+ const struct uniapi_party_created *api = msg;
+
+ uni_print_cref(NULL, 0, &api->cref, cx);
+ uni_print_eol(cx);
+ uni_print_ie(NULL, 0, UNI_IE_EPREF,
+ (const union uni_ieall *)&api->epref, cx);
+ break;
+ }
+
+ case UNIAPI_PARTY_DESTROYED:
+ {
+ const struct uniapi_party_destroyed *api = msg;
+
+ uni_print_cref(NULL, 0, &api->cref, cx);
+ uni_print_eol(cx);
+ uni_print_ie(NULL, 0, UNI_IE_EPREF,
+ (const union uni_ieall *)&api->epref, cx);
+ break;
+ }
+
+ case UNIAPI_LINK_ESTABLISH_request:
+ case UNIAPI_LINK_ESTABLISH_confirm:
+ case UNIAPI_LINK_RELEASE_request:
+ case UNIAPI_LINK_RELEASE_confirm:
+ break;
+
+ case UNIAPI_RESET_request:
+ {
+ const struct uniapi_reset_request *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_ie(NULL, 0, UNI_IE_RESTART,
+ (const union uni_ieall *)&api->restart, cx);
+ uni_print_eol(cx);
+ uni_print_ie(NULL, 0, UNI_IE_CONNID,
+ (const union uni_ieall *)&api->restart, cx);
+ break;
+ }
+
+ case UNIAPI_RESET_confirm:
+ {
+ const struct uniapi_reset_confirm *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_ie(NULL, 0, UNI_IE_RESTART,
+ (const union uni_ieall *)&api->restart, cx);
+ uni_print_eol(cx);
+ uni_print_ie(NULL, 0, UNI_IE_CONNID,
+ (const union uni_ieall *)&api->restart, cx);
+ break;
+ }
+
+ case UNIAPI_RESET_indication:
+ {
+ const struct uniapi_reset_indication *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_ie(NULL, 0, UNI_IE_RESTART,
+ (const union uni_ieall *)&api->restart, cx);
+ uni_print_eol(cx);
+ uni_print_ie(NULL, 0, UNI_IE_CONNID,
+ (const union uni_ieall *)&api->restart, cx);
+ break;
+ }
+
+ case UNIAPI_RESET_ERROR_indication:
+ {
+ const struct uniapi_reset_error_indication *api = msg;
+ static const struct uni_print_tbl reason[] = {
+#define DEF(NAME, VALUE, STR) { STR, VALUE },
+ UNIAPI_DEF_RESET_ERRORS(DEF)
+#undef DEF
+ { NULL, 0 }
+ };
+ static const struct uni_print_tbl source[] = {
+ { "start", 0 },
+ { "respond", 1 },
+ { NULL, 0 }
+ };
+
+ uni_print_eol(cx);
+ uni_print_tbl("source", api->source, source, cx);
+ uni_print_tbl("reason", api->reason, reason, cx);
+ break;
+ }
+
+ case UNIAPI_RESET_response:
+ {
+ const struct uniapi_reset_response *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_ie(NULL, 0, UNI_IE_RESTART,
+ (const union uni_ieall *)&api->restart, cx);
+ uni_print_eol(cx);
+ uni_print_ie(NULL, 0, UNI_IE_CONNID,
+ (const union uni_ieall *)&api->restart, cx);
+ break;
+ }
+
+ case UNIAPI_RESET_ERROR_response:
+ {
+ const struct uniapi_reset_error_response *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_ie(NULL, 0, UNI_IE_CAUSE,
+ (const union uni_ieall *)&api->cause, cx);
+ break;
+ }
+
+ case UNIAPI_RESET_STATUS_indication:
+ {
+ const struct uniapi_reset_status_indication *api = msg;
+
+ uni_print_cref(NULL, 0, &api->cref, cx);
+ uni_print_eol(cx);
+ uni_print_ie(NULL, 0, UNI_IE_CALLSTATE,
+ (const union uni_ieall *)&api->callstate, cx);
+ uni_print_eol(cx);
+ uni_print_ie(NULL, 0, UNI_IE_CAUSE,
+ (const union uni_ieall *)&api->cause, cx);
+ break;
+ }
+
+ case UNIAPI_SETUP_request:
+ {
+ const struct uniapi_setup_request *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_SETUP,
+ (const union uni_msgall *)&api->setup, cx);
+ break;
+ }
+
+ case UNIAPI_SETUP_indication:
+ {
+ const struct uniapi_setup_indication *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_SETUP,
+ (const union uni_msgall *)&api->setup, cx);
+ break;
+ }
+
+ case UNIAPI_SETUP_response:
+ {
+ const struct uniapi_setup_response *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_CONNECT,
+ (const union uni_msgall *)&api->connect, cx);
+ break;
+ }
+
+ case UNIAPI_SETUP_confirm:
+ {
+ const struct uniapi_setup_confirm *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_CONNECT,
+ (const union uni_msgall *)&api->connect, cx);
+ break;
+ }
+
+ case UNIAPI_SETUP_COMPLETE_indication:
+ {
+ const struct uniapi_setup_complete_indication *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_CONNECT_ACK,
+ (const union uni_msgall *)&api->connect_ack, cx);
+ break;
+ }
+
+ case UNIAPI_SETUP_COMPLETE_request:
+ {
+ const struct uniapi_setup_complete_request *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_CONNECT_ACK,
+ (const union uni_msgall *)&api->connect_ack, cx);
+ break;
+ }
+
+ case UNIAPI_ALERTING_request:
+ {
+ const struct uniapi_alerting_request *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_ALERTING,
+ (const union uni_msgall *)&api->alerting, cx);
+ break;
+ }
+
+ case UNIAPI_ALERTING_indication:
+ {
+ const struct uniapi_alerting_indication *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_ALERTING,
+ (const union uni_msgall *)&api->alerting, cx);
+ break;
+ }
+
+ case UNIAPI_PROCEEDING_request:
+ {
+ const struct uniapi_proceeding_request *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_CALL_PROC,
+ (const union uni_msgall *)&api->call_proc, cx);
+ break;
+ }
+
+ case UNIAPI_PROCEEDING_indication:
+ {
+ const struct uniapi_proceeding_indication *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_CALL_PROC,
+ (const union uni_msgall *)&api->call_proc, cx);
+ break;
+ }
+
+ case UNIAPI_RELEASE_request:
+ {
+ const struct uniapi_release_request *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_RELEASE,
+ (const union uni_msgall *)&api->release, cx);
+ break;
+ }
+
+ case UNIAPI_RELEASE_indication:
+ {
+ const struct uniapi_release_indication *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_RELEASE,
+ (const union uni_msgall *)&api->release, cx);
+ break;
+ }
+
+ case UNIAPI_RELEASE_response:
+ {
+ const struct uniapi_release_response *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_RELEASE_COMPL,
+ (const union uni_msgall *)&api->release_compl, cx);
+ break;
+ }
+ case UNIAPI_RELEASE_confirm:
+ {
+ const struct uniapi_release_confirm *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_RELEASE,
+ (const union uni_msgall *)&api->release, cx);
+ break;
+ }
+
+ case UNIAPI_NOTIFY_request:
+ {
+ const struct uniapi_notify_request *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_NOTIFY,
+ (const union uni_msgall *)&api->notify, cx);
+ break;
+ }
+
+ case UNIAPI_NOTIFY_indication:
+ {
+ const struct uniapi_notify_indication *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_NOTIFY,
+ (const union uni_msgall *)&api->notify, cx);
+ break;
+ }
+
+ case UNIAPI_STATUS_indication:
+ {
+ const struct uniapi_status_indication *api = msg;
+
+ uni_print_cref(NULL, 0, &api->cref, cx);
+ uni_print_eol(cx);
+ uni_print_entry(cx, "my_state", "U%u", api->my_state);
+ uni_print_entry(cx, "my_cause", "%s",
+ uni_ie_cause2str(UNI_CODING_ITU, api->my_cause));
+ uni_print_eol(cx);
+ uni_print_ie(NULL, 0, UNI_IE_CALLSTATE,
+ (const union uni_ieall *)&api->his_state, cx);
+ uni_print_eol(cx);
+ uni_print_ie(NULL, 0, UNI_IE_CAUSE,
+ (const union uni_ieall *)&api->his_cause, cx);
+ uni_print_eol(cx);
+ uni_print_ie(NULL, 0, UNI_IE_EPREF,
+ (const union uni_ieall *)&api->epref, cx);
+ break;
+ }
+
+ case UNIAPI_STATUS_ENQUIRY_request:
+ {
+ const struct uniapi_status_enquiry_request *api = msg;
+
+ uni_print_cref(NULL, 0, &api->cref, cx);
+ uni_print_eol(cx);
+ uni_print_ie(NULL, 0, UNI_IE_EPREF,
+ (const union uni_ieall *)&api->epref, cx);
+ break;
+ }
+
+ case UNIAPI_ADD_PARTY_request:
+ {
+ const struct uniapi_add_party_request *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_ADD_PARTY,
+ (const union uni_msgall *)&api->add, cx);
+ break;
+ }
+
+ case UNIAPI_ADD_PARTY_indication:
+ {
+ const struct uniapi_add_party_indication *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_ADD_PARTY,
+ (const union uni_msgall *)&api->add, cx);
+ break;
+ }
+
+ case UNIAPI_PARTY_ALERTING_request:
+ {
+ const struct uniapi_party_alerting_request *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_PARTY_ALERTING,
+ (const union uni_msgall *)&api->alert, cx);
+ break;
+ }
+
+ case UNIAPI_PARTY_ALERTING_indication:
+ {
+ const struct uniapi_party_alerting_indication *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_PARTY_ALERTING,
+ (const union uni_msgall *)&api->alert, cx);
+ break;
+ }
+
+ case UNIAPI_ADD_PARTY_ACK_request:
+ {
+ const struct uniapi_add_party_ack_request *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_ADD_PARTY_ACK,
+ (const union uni_msgall *)&api->ack, cx);
+ break;
+ }
+
+ case UNIAPI_ADD_PARTY_ACK_indication:
+ {
+ const struct uniapi_add_party_ack_indication *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_ADD_PARTY_ACK,
+ (const union uni_msgall *)&api->ack, cx);
+ break;
+ }
+
+ case UNIAPI_ADD_PARTY_REJ_request:
+ {
+ const struct uniapi_add_party_rej_request *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_ADD_PARTY_REJ,
+ (const union uni_msgall *)&api->rej, cx);
+ break;
+ }
+
+ case UNIAPI_ADD_PARTY_REJ_indication:
+ {
+ const struct uniapi_add_party_rej_indication *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_ADD_PARTY_REJ,
+ (const union uni_msgall *)&api->rej, cx);
+ break;
+ }
+
+ case UNIAPI_DROP_PARTY_request:
+ {
+ const struct uniapi_drop_party_request *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_DROP_PARTY,
+ (const union uni_msgall *)&api->drop, cx);
+ break;
+ }
+
+ case UNIAPI_DROP_PARTY_indication:
+ {
+ const struct uniapi_drop_party_indication *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_DROP_PARTY,
+ (const union uni_msgall *)&api->drop, cx);
+ break;
+ }
+
+ case UNIAPI_DROP_PARTY_ACK_request:
+ {
+ const struct uniapi_drop_party_ack_request *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_DROP_PARTY_ACK,
+ (const union uni_msgall *)&api->ack, cx);
+ break;
+ }
+
+ case UNIAPI_DROP_PARTY_ACK_indication:
+ {
+ const struct uniapi_drop_party_ack_indication *api = msg;
+
+ uni_print_eol(cx);
+ uni_print_msg(NULL, 0, UNI_DROP_PARTY,
+ (const union uni_msgall *)&api->drop, cx);
+ uni_print_eol(cx);
+ uni_print_ie(NULL, 0, UNI_IE_CRANKBACK,
+ (const union uni_ieall *)&api->crankback, cx);
+ break;
+ }
+
+ case UNIAPI_ABORT_CALL_request:
+ {
+ const struct uniapi_abort_call_request *api = msg;
+
+ uni_print_cref(NULL, 0, &api->cref, cx);
+ break;
+ }
+ }
+
+ out:
+ cx->dont_init = old_dont_init;
+}
diff --git a/sys/contrib/ngatm/netnatm/sig/sig_reset.c b/sys/contrib/ngatm/netnatm/sig/sig_reset.c
new file mode 100644
index 0000000..b5b4a5e
--- /dev/null
+++ b/sys/contrib/ngatm/netnatm/sig/sig_reset.c
@@ -0,0 +1,824 @@
+/*
+ * 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/sig/sig_reset.c,v 1.5 2003/09/24 10:27:50 hbb Exp $
+ *
+ * Reset-start and reset-respond
+ */
+
+#include <netnatm/unimsg.h>
+#include <netnatm/saal/sscfudef.h>
+#include <netnatm/msg/unistruct.h>
+#include <netnatm/msg/unimsglib.h>
+#include <netnatm/sig/uni.h>
+
+#include <netnatm/sig/unipriv.h>
+#include <netnatm/sig/unimkmsg.h>
+
+static void response_restart(struct uni *, struct uni_msg *, struct uni_all *);
+static void response_status(struct uni *, struct uni_msg *, struct uni_all *);
+
+static void response_t317(struct uni *);
+
+static void response_error(struct uni *, struct uniapi_reset_error_response *, u_int32_t cookie);
+static void response_response(struct uni *, struct uniapi_reset_response *, u_int32_t);
+
+static void start_request(struct uni *, struct uniapi_reset_request *, u_int32_t);
+
+static void start_t316(struct uni *);
+
+static void start_restart_ack(struct uni *, struct uni_msg *, struct uni_all *);
+static void start_status(struct uni *, struct uni_msg *, struct uni_all *);
+
+static int restart_forward(struct uni *, const struct uni_all *);
+
+#define DEF_PRIV_SIG(NAME, FROM) [SIG##NAME] "SIG"#NAME,
+static const char *const start_sigs[] = {
+ DEF_START_SIGS
+};
+#undef DEF_PRIV_SIG
+
+#define DEF_PRIV_SIG(NAME, FROM) [SIG##NAME] "SIG"#NAME,
+static const char *const respond_sigs[] = {
+ DEF_RESPOND_SIGS
+};
+#undef DEF_PRIV_SIG
+
+TIMER_FUNC_UNI(t317, t317_func)
+TIMER_FUNC_UNI(t316, t316_func)
+
+/*
+ * Reset-Start process.
+ */
+void
+uni_sig_start(struct uni *uni, u_int sig, u_int32_t cookie,
+ struct uni_msg *m, struct uni_all *u)
+{
+ if (sig >= SIGS_END) {
+ VERBOSE(uni, UNI_FAC_ERR, 1, "Signal %d outside of range to "
+ "Reset-Start", sig);
+ if (m)
+ uni_msg_destroy(m);
+ if (u)
+ UNI_FREE(u);
+ return;
+ }
+
+ VERBOSE(uni, UNI_FAC_RESTART, 1,
+ "Signal %s in state %u of Reset-Start; cookie %u",
+ start_sigs[sig], uni->glob_start, cookie);
+
+ switch (sig) {
+
+ /*
+ * User requests
+ */
+ case SIGS_RESET_request:
+ start_request(uni,
+ uni_msg_rptr(m, struct uniapi_reset_request *), cookie);
+ uni_msg_destroy(m);
+ break;
+
+ /*
+ * Timers
+ */
+ case SIGS_T316:
+ start_t316(uni);
+ break;
+
+ /*
+ * SAAL
+ */
+ case SIGS_RESTART_ACK:
+ start_restart_ack(uni, m, u);
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+ break;
+
+ case SIGS_STATUS:
+ start_status(uni, m, u);
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+ break;
+
+ case SIGS_END:
+ break;
+ }
+}
+
+/*
+ * Reset-request from USER.
+ *
+ * Q.2931:Reset-Start 1/2
+ */
+static void
+start_request(struct uni *uni, struct uniapi_reset_request *req, u_int32_t cookie)
+{
+ struct uni_all *resp;
+ int err;
+
+ if (uni->glob_start != UNI_CALLSTATE_REST0) {
+ uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0);
+ return;
+ }
+
+ if ((resp = UNI_ALLOC()) == NULL) {
+ uniapi_uni_error(uni, UNIAPI_ERROR_NOMEM, cookie, 0);
+ return;
+ }
+
+ MK_MSG_ORIG(resp, UNI_RESTART, 0, 0);
+ resp->u.restart.restart = req->restart;
+ resp->u.restart.connid = req->connid;
+
+ if (restart_forward(uni, resp))
+ return;
+
+ uni->connid_start = req->connid;
+ uni->restart_start = req->restart;
+
+ if ((err = uni_send_output(resp, uni)) != 0)
+ uniapi_uni_error(uni, UNIAPI_ERROR_ENCODING, cookie, 0);
+ UNI_FREE(resp);
+ if (err)
+ return;
+
+ uni->cnt316 = 0;
+ TIMER_START_UNI(uni, t316, uni->timer316);
+ uni->glob_start = UNI_CALLSTATE_REST1;
+
+ VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 1");
+
+
+ uniapi_uni_error(uni, UNIAPI_OK, cookie, 0);
+}
+
+/*
+ * T316 timeout function
+ */
+static void
+t316_func(struct uni *uni)
+{
+ uni_enq_start(uni, SIGS_T316, 0, NULL, NULL);
+}
+
+/*
+ * Q.2931:Reset-Start 1/2
+ */
+static void
+start_t316(struct uni *uni)
+{
+ if (uni->glob_start != UNI_CALLSTATE_REST1) {
+ VERBOSE0(uni, UNI_FAC_ERR, "T316 in state %d",
+ uni->glob_start);
+ return;
+ }
+
+ if (++uni->cnt316 == uni->init316) {
+ struct uni_msg *app;
+ struct uniapi_reset_error_indication *resp;
+
+ VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start error");
+
+ resp = ALLOC_API(struct uniapi_reset_error_indication, app);
+ if (resp != NULL) {
+ resp->source = 0;
+ resp->reason = UNIAPI_RESET_ERROR_NO_RESPONSE,
+
+ uni->funcs->uni_output(uni, uni->arg,
+ UNIAPI_RESET_ERROR_indication, 0, app);
+ }
+
+ uni->glob_start = UNI_CALLSTATE_REST0;
+ VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 0");
+ } else {
+ struct uni_all *resp;
+
+ if ((resp = UNI_ALLOC()) == NULL)
+ return;
+
+ MK_MSG_ORIG(resp, UNI_RESTART, 0, 0);
+ resp->u.restart.restart = uni->restart_start;
+ resp->u.restart.connid = uni->connid_start;
+
+ (void)uni_send_output(resp, uni);
+
+ UNI_FREE(resp);
+
+ TIMER_START_UNI(uni, t316, uni->timer316);
+ }
+}
+
+/*
+ * Got RESTART_ACK.
+ */
+static void
+start_restart_ack(struct uni *uni, struct uni_msg *m, struct uni_all *u)
+{
+ enum uni_callstate new_state;
+ struct uniapi_reset_confirm *conf;
+ struct uni_msg *app;
+
+ if (uni->glob_start == UNI_CALLSTATE_REST0) {
+ uni_respond_status_mtype(uni, &u->u.hdr.cref, uni->glob_start,
+ UNI_CAUSE_MSG_INCOMP, UNI_RESTART_ACK);
+ return;
+ }
+
+ if (uni->glob_start != UNI_CALLSTATE_REST1) {
+ ASSERT(0, ("bad global call state in Reset-Start"));
+ return;
+ }
+
+ /*
+ * If body decoding fails, this is because IEs are wrong.
+ */
+ (void)uni_decode_body(m, u, &uni->cx);
+ MANDATE_IE(uni, u->u.restart_ack.restart, UNI_IE_RESTART);
+
+ if (IE_ISGOOD(u->u.restart_ack.restart)) {
+ /*
+ * Q.2931: 5.5.2.2
+ */
+ if (u->u.restart_ack.restart.rclass == UNI_RESTART_ALL &&
+ IE_ISGOOD(u->u.restart_ack.connid)) {
+ UNI_SAVE_IERR(&uni->cx, UNI_IE_CONNID,
+ u->u.restart_ack.connid.h.act,
+ UNI_IERR_UNK);
+ } else if ((u->u.restart_ack.restart.rclass == UNI_RESTART_PATH ||
+ u->u.restart_ack.restart.rclass == UNI_RESTART_CHANNEL)) {
+ MANDATE_IE(uni, u->u.restart_ack.connid, UNI_IE_CONNID);
+ }
+ }
+ /*
+ * Compare the information elements now, because
+ * we may need the new callstate for the status message
+ * below.
+ */
+ new_state = UNI_CALLSTATE_REST1;
+
+ if (IE_ISGOOD(u->u.restart_ack.restart) &&
+ IE_ISGOOD(uni->restart_start) &&
+ u->u.restart_ack.restart.rclass == uni->restart_start.rclass &&
+ !IE_ISGOOD(u->u.restart_ack.connid) == !IE_ISGOOD(uni->connid_start) &&
+ (!IE_ISGOOD(uni->connid_start) ||
+ (u->u.restart_ack.connid.vpci == uni->connid_start.vpci &&
+ u->u.restart_ack.connid.vci == uni->connid_start.vci)))
+ new_state = UNI_CALLSTATE_REST0;
+
+ switch (uni_verify(uni, u->u.hdr.act)) {
+ case VFY_RAIM:
+ case VFY_RAI:
+ uni_respond_status_verify(uni, &u->u.hdr.cref,
+ UNI_CALLSTATE_REST1, NULL, 0);
+ case VFY_I:
+ return;
+
+ case VFY_CLR:
+ uni->glob_start = UNI_CALLSTATE_REST0;
+ VERBOSE(uni, UNI_FAC_RESTART, 1,
+ "Reset-Start state := 0");
+ return;
+
+ case VFY_RAP:
+ case VFY_RAPU:
+ uni_respond_status_verify(uni, &u->u.hdr.cref,
+ new_state, NULL, 0);
+ case VFY_OK:
+ break;
+ }
+
+ if (new_state == UNI_CALLSTATE_REST1)
+ /*
+ * Q.2931: 5.5.1.2/2
+ */
+ return;
+
+ /*
+ * Build restart.confirm signal for application
+ */
+ if (!IE_ISGOOD(u->u.restart_ack.connid))
+ u->u.restart.connid.h.present = 0;
+
+
+ if ((conf = ALLOC_API(struct uniapi_reset_confirm, app)) == NULL)
+ return;
+ conf->restart = u->u.restart.restart;
+ conf->connid = u->u.restart.connid;
+
+ TIMER_STOP_UNI(uni, t316);
+
+ uni->funcs->uni_output(uni, uni->arg, UNIAPI_RESET_confirm, 0, app);
+
+ uni->glob_start = UNI_CALLSTATE_REST0;
+ VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 0");
+}
+
+/*
+ * Reset-Start got a STATUS message.
+ *
+ * Q.2931: Reset-Start 2/2
+ *
+ * In Q.2931 only CALLSTATE_REST1 is allowed, this seems silly and to contradict
+ * 5.6.12. So allow it in any state.
+ *
+ * The following states are considered compatible:
+ *
+ * Sender Receiver(we)
+ * ------ --------
+ * Rest0 Rest0 this is the normal state OK!
+ * Rest2 Rest0 this may be the result of no answer from the API
+ * on the remote end and the us finally timing out. ERROR!
+ * Rest2 Rest1 this is normal. OK!
+ * Rest0 Rest1 RESTART_ACK was probably lost. OK!
+ *
+ * All others are wrong.
+ */
+static void
+start_status(struct uni *uni, struct uni_msg *m, struct uni_all *u)
+{
+ (void)uni_decode_body(m, u, &uni->cx);
+ MANDATE_IE(uni, u->u.status.callstate, UNI_IE_CALLSTATE);
+ MANDATE_IE(uni, u->u.status.cause, UNI_IE_CAUSE);
+ switch (uni_verify(uni, u->u.hdr.act)) {
+ case VFY_CLR:
+ uni->glob_start = UNI_CALLSTATE_REST0;
+ VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 0");
+ return;
+
+ case VFY_RAIM:
+ case VFY_RAI:
+ case VFY_RAP:
+ case VFY_RAPU:
+ uni_respond_status_verify(uni, &u->u.hdr.cref, uni->glob_start,
+ NULL, 0);
+ case VFY_I:
+ case VFY_OK:
+ break;
+ }
+ if (!IE_ISGOOD(u->u.status.callstate)) {
+ /*
+ * As a result of the strange handling above, we must
+ * process a STATUS with an invalid or missing callstate!
+ */
+ return;
+ }
+ if ((u->u.status.callstate.state == UNI_CALLSTATE_REST0 &&
+ uni->glob_start == UNI_CALLSTATE_REST0) ||
+ (u->u.status.callstate.state == UNI_CALLSTATE_REST0 &&
+ uni->glob_start == UNI_CALLSTATE_REST1) ||
+ (u->u.status.callstate.state == UNI_CALLSTATE_REST2 &&
+ uni->glob_start == UNI_CALLSTATE_REST1)) {
+ /*
+ * Implementation dependend procedure:
+ * Inform the API
+ */
+ struct uniapi_reset_status_indication *resp;
+ struct uni_msg *app;
+
+ resp = ALLOC_API(struct uniapi_reset_status_indication, app);
+ if (resp == NULL)
+ return;
+ resp->cref = u->u.hdr.cref;
+ resp->callstate = u->u.status.callstate;
+ if (IE_ISGOOD(u->u.status.cause))
+ resp->cause = u->u.status.cause;
+
+ uni->funcs->uni_output(uni, uni->arg,
+ UNIAPI_RESET_STATUS_indication, 0, app);
+
+ } else {
+ struct uniapi_reset_error_indication *resp;
+ struct uni_msg *app;
+
+ resp = ALLOC_API(struct uniapi_reset_error_indication, app);
+ if (resp != NULL) {
+ resp->source = 0;
+ resp->reason = UNIAPI_RESET_ERROR_PEER_INCOMP_STATE,
+
+ uni->funcs->uni_output(uni, uni->arg,
+ UNIAPI_RESET_ERROR_indication, 0, app);
+ }
+ }
+}
+
+/************************************************************/
+/*
+ * Reset-Respond process.
+ */
+void
+uni_sig_respond(struct uni *uni, u_int sig, u_int32_t cookie,
+ struct uni_msg *m, struct uni_all *u)
+{
+ if (sig >= SIGR_END) {
+ VERBOSE(uni, UNI_FAC_ERR, 1, "Signal %d outside of range to "
+ "Reset-Respond", sig);
+ if (m)
+ uni_msg_destroy(m);
+ if (u)
+ UNI_FREE(u);
+ return;
+ }
+
+ VERBOSE(uni, UNI_FAC_RESTART, 1,
+ "Signal %s in state %u of Reset-Respond; cookie %u",
+ respond_sigs[sig], uni->glob_respond, cookie);
+
+ switch (sig) {
+
+ /*
+ * SAAL
+ */
+ case SIGR_RESTART:
+ response_restart(uni, m, u);
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+ break;
+
+ case SIGR_STATUS:
+ response_status(uni, m, u);
+ uni_msg_destroy(m);
+ UNI_FREE(u);
+ break;
+
+ /*
+ * User
+ */
+ case SIGR_RESET_ERROR_response:
+ response_error(uni,
+ uni_msg_rptr(m, struct uniapi_reset_error_response *),
+ cookie);
+ uni_msg_destroy(m);
+ break;
+
+ case SIGR_RESET_response:
+ response_response(uni,
+ uni_msg_rptr(m, struct uniapi_reset_response *), cookie);
+ uni_msg_destroy(m);
+ break;
+
+ /*
+ * Timers
+ */
+ case SIGR_T317:
+ response_t317(uni);
+ return;
+
+ case SIGR_END:
+ break;
+ }
+}
+
+/*
+ * Send a RELEASE_COMPLETE to all affected calls as per
+ * F.2.3(3)
+ */
+static int
+restart_forward(struct uni *uni, const struct uni_all *u)
+{
+ struct call *c;
+ struct uni_all *resp;
+
+ if ((resp = UNI_ALLOC()) == NULL)
+ return (-1);
+
+ TAILQ_FOREACH(c, &uni->calls, link) {
+ if (u->u.restart.restart.rclass == UNI_RESTART_ALL ||
+ (IE_ISPRESENT(c->connid) &&
+ u->u.restart.connid.vpci == c->connid.vpci &&
+ (u->u.restart.restart.rclass == UNI_RESTART_PATH ||
+ u->u.restart.connid.vci == c->connid.vci))) {
+ MK_MSG_ORIG(resp, UNI_RELEASE_COMPL, c->cref, c->mine);
+ uni_release_compl(c, resp);
+ }
+ }
+
+ UNI_FREE(resp);
+ return (0);
+}
+
+/*
+ * Respond process got a restart message.
+ * Doesn't free the messages.
+ */
+static void
+response_restart(struct uni *uni, struct uni_msg *m, struct uni_all *u)
+{
+ struct uni_msg *app;
+ struct uniapi_reset_indication *ind;
+
+ if (uni->glob_respond == UNI_CALLSTATE_REST0) {
+ /*
+ * If body decoding fails, this is because IEs are wrong.
+ */
+ (void)uni_decode_body(m, u, &uni->cx);
+ MANDATE_IE(uni, u->u.restart.restart, UNI_IE_RESTART);
+ if (IE_ISGOOD(u->u.restart.restart)) {
+ /*
+ * Q.2931: 5.5.2.2
+ */
+ if (u->u.restart.restart.rclass == UNI_RESTART_ALL &&
+ IE_ISGOOD(u->u.restart.connid)) {
+ UNI_SAVE_IERR(&uni->cx, UNI_IE_CONNID,
+ u->u.restart.connid.h.act,
+ UNI_IERR_UNK);
+ } else if ((u->u.restart.restart.rclass == UNI_RESTART_PATH ||
+ u->u.restart.restart.rclass == UNI_RESTART_CHANNEL)) {
+ MANDATE_IE(uni, u->u.restart.connid, UNI_IE_CONNID);
+ }
+ }
+ switch (uni_verify(uni, u->u.hdr.act)) {
+ case VFY_RAIM:
+ case VFY_RAI:
+ uni_respond_status_verify(uni, &u->u.hdr.cref,
+ UNI_CALLSTATE_REST0, NULL, 0);
+ case VFY_CLR:
+ case VFY_I:
+ return;
+
+ case VFY_RAP:
+ case VFY_RAPU:
+ uni_respond_status_verify(uni, &u->u.hdr.cref,
+ UNI_CALLSTATE_REST2, NULL, 0);
+ case VFY_OK:
+ break;
+ }
+ if (!IE_ISGOOD(u->u.restart.connid))
+ u->u.restart.connid.h.present = 0;
+
+ /*
+ * Send a RELEASE_COMPLETE to all affected calls as per
+ * F.2.3(3)
+ */
+ if (restart_forward(uni, u))
+ return;
+
+ /*
+ * Build restart signal for application
+ */
+ if ((ind = ALLOC_API(struct uniapi_reset_indication, app)) == NULL)
+ return;
+
+ ind->restart = u->u.restart.restart;
+ ind->connid = u->u.restart.connid;
+
+ uni_enq_coord(uni, SIGO_RESET_indication, 0, app);
+
+ TIMER_START_UNI(uni, t317, uni->timer317);
+ uni->glob_respond = UNI_CALLSTATE_REST2;
+
+ VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond state := 2");
+
+
+ } else if (uni->glob_respond == UNI_CALLSTATE_REST2) {
+ /*
+ * No need to decode the message. It is unexpected in this
+ * state so return a status.
+ */
+ uni_respond_status_mtype(uni, &u->u.hdr.cref, uni->glob_respond,
+ UNI_CAUSE_MSG_INCOMP, UNI_RESTART);
+
+
+ } else
+ ASSERT(0, ("bad global call state in responder"));
+}
+
+static void
+response_t317(struct uni *uni)
+{
+ struct uniapi_reset_error_indication *resp;
+ struct uni_msg *app;
+
+ if (uni->glob_respond != UNI_CALLSTATE_REST2) {
+ VERBOSE0(uni, UNI_FAC_ERR, "T317 in state %d",
+ uni->glob_respond);
+ return;
+ }
+
+ VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond error");
+
+ if ((resp = ALLOC_API(struct uniapi_reset_error_indication, app)) != NULL) {
+ resp->source = 1;
+ resp->reason = UNIAPI_RESET_ERROR_NO_CONFIRM;
+
+ uni->funcs->uni_output(uni, uni->arg,
+ UNIAPI_RESET_ERROR_indication, 0, app);
+ }
+
+ uni->glob_respond = UNI_CALLSTATE_REST0;
+ VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond state := 0");
+}
+
+/*
+ * Error response from USER
+ */
+static void
+response_error(struct uni *uni, struct uniapi_reset_error_response *c,
+ u_int32_t cookie)
+{
+ struct uni_all *resp;
+
+ if (uni->glob_respond != UNI_CALLSTATE_REST2) {
+ uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0);
+ return;
+ }
+
+ if ((resp = UNI_ALLOC()) == NULL) {
+ uniapi_uni_error(uni, UNIAPI_ERROR_NOMEM, cookie, 0);
+ return;
+ }
+
+ MK_MSG_ORIG(resp, UNI_STATUS, 0, 1);
+ MK_IE_CALLSTATE(resp->u.status.callstate, UNI_CALLSTATE_REST2);
+
+ if (IE_ISGOOD(c->cause))
+ resp->u.status.cause = c->cause;
+ else {
+ MK_IE_CAUSE(resp->u.status.cause, UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_CHANNEL_NEX);
+ if (IE_ISGOOD(uni->connid_respond))
+ ADD_CAUSE_CHANNID(resp->u.status.cause,
+ uni->connid_respond.vpci,
+ uni->connid_respond.vci);
+ }
+
+ if (uni_send_output(resp, uni) != 0) {
+ uniapi_uni_error(uni, UNIAPI_ERROR_ENCODING, cookie, 0);
+ UNI_FREE(resp);
+ return;
+ }
+
+ uniapi_uni_error(uni, UNIAPI_OK, cookie, 0);
+}
+
+/*
+ * Reset-response from user.
+ */
+static void
+response_response(struct uni *uni, struct uniapi_reset_response *arg,
+ u_int32_t cookie)
+{
+ struct uni_all *resp;
+
+ if (uni->glob_respond != UNI_CALLSTATE_REST2) {
+ uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0);
+ return;
+ }
+
+ if (!IE_ISGOOD(arg->restart)) {
+ uniapi_uni_error(uni, UNIAPI_ERROR_MISSING_IE, cookie, 0);
+ return;
+ }
+
+ if ((resp = UNI_ALLOC()) == NULL) {
+ uniapi_uni_error(uni, UNIAPI_ERROR_NOMEM, cookie, 0);
+ return;
+ }
+
+ TIMER_STOP_UNI(uni, t317);
+
+ MK_MSG_ORIG(resp, UNI_RESTART_ACK, 0, 1);
+ resp->u.restart.restart = arg->restart;
+ if (IE_ISGOOD(arg->connid))
+ resp->u.restart.connid = arg->connid;
+
+ if (uni_send_output(resp, uni) != 0) {
+ uniapi_uni_error(uni, UNIAPI_ERROR_ENCODING, cookie, 0);
+ UNI_FREE(resp);
+ return;
+ }
+
+ UNI_FREE(resp);
+
+ uni->glob_respond = UNI_CALLSTATE_REST0;
+ VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond state := 0");
+
+ uniapi_uni_error(uni, UNIAPI_OK, cookie, 0);
+}
+
+/*
+ * Reset-Response got a STATUS message.
+ *
+ * Q.2931: Reset-Response 2/2
+ *
+ * In Q.2931 only CALLSTATE_REST2 is allowed, this seems silly and to contradict
+ * 5.6.12. So allow it in any state.
+ *
+ * The following states are considered compatible:
+ *
+ * Sender Receiver
+ * ------ --------
+ * Rest0 Rest0 this is the normal state OK!
+ * Rest0 Rest2 this may be the result of no answer from the API
+ * and the Sender finally timing out. ERROR!
+ * Rest1 Rest2 this is normal. OK!
+ * Rest1 Rest0 RESTART_ACK was probably lost. OK!
+ *
+ * All others are wrong.
+ */
+static void
+response_status(struct uni *uni, struct uni_msg *m, struct uni_all *u)
+{
+ (void)uni_decode_body(m, u, &uni->cx);
+ MANDATE_IE(uni, u->u.status.callstate, UNI_IE_CALLSTATE);
+ MANDATE_IE(uni, u->u.status.cause, UNI_IE_CAUSE);
+ switch (uni_verify(uni, u->u.hdr.act)) {
+ case VFY_CLR:
+ if (uni->proto == UNIPROTO_UNI40U) {
+ uni->glob_respond = UNI_CALLSTATE_REST0;
+ VERBOSE(uni, UNI_FAC_RESTART, 1,
+ "Reset-Respond state := 0");
+ return;
+ }
+ break;
+
+ case VFY_RAIM:
+ case VFY_RAI:
+ case VFY_RAP:
+ case VFY_RAPU:
+ uni_respond_status_verify(uni, &u->u.hdr.cref,
+ uni->glob_respond, NULL, 0);
+ case VFY_I:
+ case VFY_OK:
+ break;
+ }
+ if (!IE_ISGOOD(u->u.status.callstate)) {
+ /*
+ * As a result of the strange handling above, we must
+ * process a STATUS with an invalid or missing callstate!
+ */
+ return;
+ }
+ if ((u->u.status.callstate.state == UNI_CALLSTATE_REST0 &&
+ uni->glob_respond == UNI_CALLSTATE_REST0) ||
+ (u->u.status.callstate.state == UNI_CALLSTATE_REST1 &&
+ uni->glob_respond == UNI_CALLSTATE_REST0) ||
+ (u->u.status.callstate.state == UNI_CALLSTATE_REST1 &&
+ uni->glob_respond == UNI_CALLSTATE_REST2)) {
+ /*
+ * Implementation dependend procedure:
+ * Inform the API
+ */
+ struct uniapi_reset_status_indication *resp;
+ struct uni_msg *app;
+
+ resp = ALLOC_API(struct uniapi_reset_status_indication, app);
+ if (resp == NULL)
+ return;
+
+ resp->cref = u->u.hdr.cref;
+ resp->callstate = u->u.status.callstate;
+ if (IE_ISGOOD(u->u.status.cause))
+ resp->cause = u->u.status.cause;
+
+ uni->funcs->uni_output(uni, uni->arg,
+ UNIAPI_RESET_STATUS_indication, 0, app);
+
+ } else {
+ struct uniapi_reset_error_indication *resp;
+ struct uni_msg *app;
+
+ resp = ALLOC_API(struct uniapi_reset_error_indication, app);
+ if (resp != NULL) {
+ resp->source = 1;
+ resp->reason = UNIAPI_RESET_ERROR_PEER_INCOMP_STATE,
+
+ uni->funcs->uni_output(uni, uni->arg,
+ UNIAPI_RESET_ERROR_indication, 0, app);
+ }
+ }
+}
+
+/*
+ * T317 timeout function
+ */
+static void
+t317_func(struct uni *uni)
+{
+ uni_enq_resp(uni, SIGR_T317, 0, NULL, NULL);
+}
diff --git a/sys/contrib/ngatm/netnatm/sig/sig_uni.c b/sys/contrib/ngatm/netnatm/sig/sig_uni.c
new file mode 100644
index 0000000..3755881
--- /dev/null
+++ b/sys/contrib/ngatm/netnatm/sig/sig_uni.c
@@ -0,0 +1,749 @@
+/*
+ * 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/sig/sig_uni.c,v 1.4 2003/09/24 10:27:50 hbb Exp $
+ *
+ * Instance handling
+ */
+
+#include <netnatm/unimsg.h>
+#include <netnatm/saal/sscopdef.h>
+#include <netnatm/saal/sscfudef.h>
+#include <netnatm/msg/unistruct.h>
+#include <netnatm/msg/unimsglib.h>
+#include <netnatm/sig/uni.h>
+#include <netnatm/sig/unisig.h>
+
+#include <netnatm/sig/unipriv.h>
+
+#ifdef UNICORE
+UNICORE
+#endif
+
+#define STR(S) [S] #S
+static const char *custat_names[] = {
+ STR(CU_STAT0),
+ STR(CU_STAT1),
+ STR(CU_STAT2),
+ STR(CU_STAT3),
+};
+static const char *globstat_names[] = {
+ STR(UNI_CALLSTATE_REST0),
+ STR(UNI_CALLSTATE_REST1),
+ STR(UNI_CALLSTATE_REST2),
+};
+
+static const char *sig_names[] = {
+ STR(UNIAPI_ERROR),
+ STR(UNIAPI_CALL_CREATED),
+ STR(UNIAPI_CALL_DESTROYED),
+ STR(UNIAPI_PARTY_CREATED),
+ STR(UNIAPI_PARTY_DESTROYED),
+ STR(UNIAPI_LINK_ESTABLISH_request),
+ STR(UNIAPI_LINK_ESTABLISH_confirm),
+ STR(UNIAPI_LINK_RELEASE_request),
+ STR(UNIAPI_LINK_RELEASE_confirm),
+ STR(UNIAPI_RESET_request),
+ STR(UNIAPI_RESET_confirm),
+ STR(UNIAPI_RESET_indication),
+ STR(UNIAPI_RESET_ERROR_indication),
+ STR(UNIAPI_RESET_response),
+ STR(UNIAPI_RESET_ERROR_response),
+ STR(UNIAPI_RESET_STATUS_indication),
+ STR(UNIAPI_SETUP_request),
+ STR(UNIAPI_SETUP_indication),
+ STR(UNIAPI_SETUP_response),
+ STR(UNIAPI_SETUP_confirm),
+ STR(UNIAPI_SETUP_COMPLETE_indication),
+ STR(UNIAPI_SETUP_COMPLETE_request),
+ STR(UNIAPI_ALERTING_request),
+ STR(UNIAPI_ALERTING_indication),
+ STR(UNIAPI_PROCEEDING_request),
+ STR(UNIAPI_PROCEEDING_indication),
+ STR(UNIAPI_RELEASE_request),
+ STR(UNIAPI_RELEASE_indication),
+ STR(UNIAPI_RELEASE_response),
+ STR(UNIAPI_RELEASE_confirm),
+ STR(UNIAPI_NOTIFY_request),
+ STR(UNIAPI_NOTIFY_indication),
+ STR(UNIAPI_STATUS_indication),
+ STR(UNIAPI_STATUS_ENQUIRY_request),
+ STR(UNIAPI_ADD_PARTY_request),
+ STR(UNIAPI_ADD_PARTY_indication),
+ STR(UNIAPI_PARTY_ALERTING_request),
+ STR(UNIAPI_PARTY_ALERTING_indication),
+ STR(UNIAPI_ADD_PARTY_ACK_request),
+ STR(UNIAPI_ADD_PARTY_ACK_indication),
+ STR(UNIAPI_ADD_PARTY_REJ_request),
+ STR(UNIAPI_ADD_PARTY_REJ_indication),
+ STR(UNIAPI_DROP_PARTY_request),
+ STR(UNIAPI_DROP_PARTY_indication),
+ STR(UNIAPI_DROP_PARTY_ACK_request),
+ STR(UNIAPI_DROP_PARTY_ACK_indication),
+ STR(UNIAPI_ABORT_CALL_request),
+};
+
+static const char *verb_names[] = {
+# define UNI_DEBUG_DEFINE(D) [UNI_FAC_##D] #D,
+ UNI_DEBUG_FACILITIES
+# undef UNI_DEBUG_DEFINE
+};
+
+const char *
+uni_facname(enum uni_verb fac)
+{
+ static char buf[40];
+
+ if (fac >= UNI_MAXFACILITY) {
+ sprintf(buf, "FAC%u", fac);
+ return (buf);
+ }
+ return (verb_names[fac]);
+}
+
+const char *
+uni_signame(enum uni_sig sig)
+{
+ static char buf[40];
+
+ if (sig >= UNIAPI_MAXSIG) {
+ sprintf(buf, "UNIAPI_SIG%u", sig);
+ return (buf);
+ }
+ return (sig_names[sig]);
+}
+
+struct unicx *
+uni_context(struct uni *uni)
+{
+ return (&uni->cx);
+}
+
+static void
+uni_init(struct uni *uni)
+{
+ uni->working = 0;
+ uni->cref_alloc = 12;
+ uni->custat = CU_STAT0;
+ uni->glob_start = UNI_CALLSTATE_REST0;
+ uni->glob_respond = UNI_CALLSTATE_REST0;
+}
+
+static void
+uni_stop(struct uni *uni)
+{
+ struct call *c;
+
+ while ((c = TAILQ_FIRST(&uni->calls)) != NULL) {
+ TAILQ_REMOVE(&uni->calls, c, link);
+ uni_destroy_call(c, 1);
+ }
+
+ SIGQ_CLEAR(&uni->workq);
+ SIGQ_CLEAR(&uni->delq);
+}
+
+/*
+ * INSTANCE HANDLING
+ */
+struct uni *
+uni_create(void *arg, const struct uni_funcs *funcs)
+{
+ struct uni *uni;
+
+ if ((uni = INS_ALLOC()) == NULL)
+ return (NULL);
+
+ uni_init(uni);
+
+ uni->funcs = funcs;
+ uni->arg = arg;
+ uni->proto = UNIPROTO_UNI40U;
+ uni->sb_tb = 0;
+ TAILQ_INIT(&uni->workq);
+ TAILQ_INIT(&uni->delq);
+ TIMER_INIT_UNI(uni, t309);
+ uni->timer309 = UNI_T309_DEFAULT;
+ TAILQ_INIT(&uni->calls);
+ uni_initcx(&uni->cx);
+ TIMER_INIT_UNI(uni, t317);
+ TIMER_INIT_UNI(uni, t316);
+
+ uni->timer301 = UNI_T301_DEFAULT;
+ uni->init303 = UNI_T303_CNT_DEFAULT;
+ uni->timer303 = UNI_T303_DEFAULT;
+ uni->init308 = UNI_T308_CNT_DEFAULT;
+ uni->timer308 = UNI_T308_DEFAULT;
+ uni->timer310 = UNI_T310U_DEFAULT;
+ uni->timer313 = UNI_T313_DEFAULT;
+ uni->init316 = UNI_T316_CNT_DEFAULT;
+ uni->timer316 = UNI_T316_DEFAULT;
+ uni->timer317 = UNI_T317_DEFAULT;
+ uni->timer322 = UNI_T322_DEFAULT;
+ uni->init322 = UNI_T322_CNT_DEFAULT;
+ uni->timer397 = UNI_T397_DEFAULT;
+ uni->timer398 = UNI_T398_DEFAULT;
+ uni->timer399 = UNI_T399U_DEFAULT;
+
+ return (uni);
+}
+
+void
+uni_destroy(struct uni *uni)
+{
+ uni_stop(uni);
+
+ TIMER_DESTROY_UNI(uni, t309);
+ TIMER_DESTROY_UNI(uni, t316);
+ TIMER_DESTROY_UNI(uni, t317);
+
+ INS_FREE(uni);
+}
+
+void
+uni_reset(struct uni *uni)
+{
+ uni_stop(uni);
+ uni_init(uni);
+}
+
+
+/*
+ * DISPATCH SSCOP SIGNAL
+ */
+void
+uni_saal_input(struct uni *uni, enum saal_sig sig, struct uni_msg *m)
+{
+ switch (sig) {
+
+ case SAAL_ESTABLISH_indication:
+ if (m != NULL)
+ uni_msg_destroy(m);
+ uni_enq_coord(uni, SIGO_SAAL_ESTABLISH_indication, 0, NULL);
+ break;
+
+ case SAAL_ESTABLISH_confirm:
+ if (m != NULL)
+ uni_msg_destroy(m);
+ uni_enq_coord(uni, SIGO_SAAL_ESTABLISH_confirm, 0, NULL);
+ break;
+
+ case SAAL_RELEASE_confirm:
+ if (m != NULL)
+ uni_msg_destroy(m);
+ uni_enq_coord(uni, SIGO_SAAL_RELEASE_confirm, 0, NULL);
+ break;
+
+ case SAAL_RELEASE_indication:
+ if (m != NULL)
+ uni_msg_destroy(m);
+ uni_enq_coord(uni, SIGO_SAAL_RELEASE_indication, 0, NULL);
+ break;
+
+ case SAAL_DATA_indication:
+ uni_enq_coord(uni, SIGO_SAAL_DATA_indication, 0, m);
+ break;
+
+ case SAAL_UDATA_indication:
+ uni_enq_coord(uni, SIGO_SAAL_UDATA_indication, 0, m);
+ break;
+
+ default:
+ VERBOSE(uni, UNI_FAC_ERR, 1, "bogus saal signal %u", sig);
+ if (m != NULL)
+ uni_msg_destroy(m);
+ break;
+ }
+}
+
+static struct {
+ const char *name;
+ enum uni_sig sig;
+ size_t arglen;
+ u_int coord_sig;
+ u_int proto;
+#define UNIU 0x01
+#define UNIN 0x02
+#define PNNI 0x04
+} maptab[] = {
+ { "LINK-ESTABLISH.request", UNIAPI_LINK_ESTABLISH_request,
+ 0,
+ SIGO_LINK_ESTABLISH_request, UNIU | UNIN },
+ { "LINK-RELEASE.request", UNIAPI_LINK_RELEASE_request,
+ 0,
+ SIGO_LINK_RELEASE_request, UNIU | UNIN },
+
+ { "RESET.request", UNIAPI_RESET_request,
+ sizeof(struct uniapi_reset_request),
+ SIGO_RESET_request, UNIU | UNIN },
+ { "RESET-ERROR.response", UNIAPI_RESET_ERROR_response,
+ sizeof(struct uniapi_reset_error_response),
+ SIGO_RESET_ERROR_response, UNIU | UNIN },
+ { "RESET.response", UNIAPI_RESET_response,
+ sizeof(struct uniapi_reset_response),
+ SIGO_RESET_response, UNIU | UNIN },
+
+ { "SETUP.request", UNIAPI_SETUP_request,
+ sizeof(struct uniapi_setup_request),
+ SIGO_SETUP_request, UNIU | UNIN },
+ { "SETUP.response", UNIAPI_SETUP_response,
+ sizeof(struct uniapi_setup_response),
+ SIGO_SETUP_response, UNIU | UNIN },
+ { "SETUP-COMPLETE.request", UNIAPI_SETUP_COMPLETE_request,
+ sizeof(struct uniapi_setup_complete_request),
+ SIGO_SETUP_COMPLETE_request, UNIN },
+ { "PROCEEDING.request", UNIAPI_PROCEEDING_request,
+ sizeof(struct uniapi_proceeding_request),
+ SIGO_PROCEEDING_request, UNIU | UNIN },
+ { "ALERTING.request", UNIAPI_ALERTING_request,
+ sizeof(struct uniapi_alerting_request),
+ SIGO_ALERTING_request, UNIU | UNIN },
+ { "RELEASE.request", UNIAPI_RELEASE_request,
+ sizeof(struct uniapi_release_request),
+ SIGO_RELEASE_request, UNIU | UNIN },
+ { "RELEASE.response", UNIAPI_RELEASE_response,
+ sizeof(struct uniapi_release_response),
+ SIGO_RELEASE_response, UNIU | UNIN },
+ { "NOTIFY.request", UNIAPI_NOTIFY_request,
+ sizeof(struct uniapi_notify_request),
+ SIGO_NOTIFY_request, UNIU | UNIN },
+ { "STATUS-ENQUIRY.request", UNIAPI_STATUS_ENQUIRY_request,
+ sizeof(struct uniapi_status_enquiry_request),
+ SIGO_STATUS_ENQUIRY_request, UNIU | UNIN },
+
+ { "ADD-PARTY.request", UNIAPI_ADD_PARTY_request,
+ sizeof(struct uniapi_add_party_request),
+ SIGO_ADD_PARTY_request, UNIU | UNIN },
+ { "ADD-PARTY-ACK.request", UNIAPI_ADD_PARTY_ACK_request,
+ sizeof(struct uniapi_add_party_ack_request),
+ SIGO_ADD_PARTY_ACK_request, UNIU | UNIN },
+ { "ADD-PARTY-REJ.request", UNIAPI_ADD_PARTY_REJ_request,
+ sizeof(struct uniapi_add_party_rej_request),
+ SIGO_ADD_PARTY_REJ_request, UNIU | UNIN },
+ { "PARTY-ALERTING.request", UNIAPI_PARTY_ALERTING_request,
+ sizeof(struct uniapi_party_alerting_request),
+ SIGO_PARTY_ALERTING_request, UNIU | UNIN },
+ { "DROP-PARTY.request", UNIAPI_DROP_PARTY_request,
+ sizeof(struct uniapi_drop_party_request),
+ SIGO_DROP_PARTY_request, UNIU | UNIN },
+ { "DROP-PARTY-ACK.request", UNIAPI_DROP_PARTY_ACK_request,
+ sizeof(struct uniapi_drop_party_ack_request),
+ SIGO_DROP_PARTY_ACK_request, UNIU | UNIN },
+
+ { "ABORT-CALL.request", UNIAPI_ABORT_CALL_request,
+ sizeof(struct uniapi_abort_call_request),
+ SIGO_ABORT_CALL_request, UNIU | UNIN },
+
+ { NULL, 0, 0, 0, 0 }
+};
+
+void
+uni_uni_input(struct uni *uni, enum uni_sig sig, u_int32_t cookie,
+ struct uni_msg *m)
+{
+ u_int i;
+
+ for (i = 0; maptab[i].name != NULL; i++) {
+ if (maptab[i].sig == sig) {
+ if (uni->proto == UNIPROTO_UNI40U) {
+ if (!(maptab[i].proto & UNIU))
+ uniapi_uni_error(uni,
+ UNIAPI_ERROR_BAD_SIGNAL, cookie, 0);
+ } else if(uni->proto == UNIPROTO_UNI40N) {
+ if (!(maptab[i].proto & UNIN))
+ uniapi_uni_error(uni,
+ UNIAPI_ERROR_BAD_SIGNAL, cookie, 0);
+ } else if(uni->proto == UNIPROTO_PNNI10) {
+ if (!(maptab[i].proto & PNNI))
+ uniapi_uni_error(uni,
+ UNIAPI_ERROR_BAD_SIGNAL, cookie, 0);
+ } else {
+ uniapi_uni_error(uni,
+ UNIAPI_ERROR_BAD_SIGNAL, cookie, 0);
+ }
+ if (uni_msg_len(m) != maptab[i].arglen) {
+ VERBOSE(uni, UNI_FAC_ERR, 1, "bogus data in %s"
+ " (expecting %zu, got %zu)", maptab[i].name,
+ maptab[i].arglen, uni_msg_len(m));
+ uni_msg_destroy(m);
+ uniapi_uni_error(uni, UNIAPI_ERROR_BAD_ARG,
+ cookie, 0);
+ return;
+ }
+ if (maptab[i].arglen == 0) {
+ uni_msg_destroy(m);
+ m = NULL;
+ }
+ VERBOSE(uni, UNI_FAC_API, 1, "got signal %s - "
+ "delivering to Coord", maptab[i].name);
+ uni_enq_coord(uni, maptab[i].coord_sig, cookie, m);
+ return;
+ }
+ }
+ VERBOSE(uni, UNI_FAC_ERR, 1, "bogus uni signal %u", sig);
+ uni_msg_destroy(m);
+ uniapi_uni_error(uni, UNIAPI_ERROR_BAD_SIGNAL, cookie, 0);
+}
+#undef UNIU
+#undef UNIN
+#undef PNNI
+
+/**************************************************************/
+
+void
+uni_work(struct uni *uni)
+{
+ struct sig *s;
+
+ if (uni->working)
+ return;
+ uni->working = 1;
+
+ while ((s = TAILQ_FIRST(&uni->workq)) != NULL) {
+ TAILQ_REMOVE(&uni->workq, s, link);
+ switch (s->type) {
+
+ case SIG_COORD:
+ uni_sig_coord(uni, s->sig, s->cookie, s->msg);
+ break;
+
+ case SIG_RESET_START:
+ uni_sig_start(uni, s->sig, s->cookie, s->msg, s->u);
+ break;
+
+ case SIG_RESET_RESP:
+ uni_sig_respond(uni, s->sig, s->cookie, s->msg, s->u);
+ break;
+
+ case SIG_CALL:
+ uni_sig_call(s->call, s->sig, s->cookie, s->msg, s->u);
+ break;
+
+ case SIG_PARTY:
+ uni_sig_party(s->party, s->sig, s->cookie, s->msg, s->u);
+ break;
+
+ default:
+ ASSERT(0, ("bad signal type"));
+ }
+ SIG_FREE(s);
+ }
+
+ uni->working = 0;
+}
+
+/*
+ * Enqueue a signal in the working queue
+ */
+void
+uni_enq_sig(struct uni *uni, u_int type, struct call *call,
+ struct party *party, u_int32_t sig, u_int32_t cookie,
+ struct uni_msg *msg, struct uni_all *u)
+{
+ struct sig *s;
+
+ if ((s = SIG_ALLOC()) != NULL) {
+ s->type = type;
+ s->sig = sig;
+ s->cookie = cookie;
+ s->msg = msg;
+ s->call = call;
+ s->party = party;
+ s->u = u;
+ TAILQ_INSERT_TAIL(&uni->workq, s, link);
+ }
+}
+
+/*
+ * Enqueue a signal in the delayed queue
+ */
+void
+uni_delenq_sig(struct uni *uni, u_int type, struct call *call,
+ struct party *party, u_int32_t sig, u_int32_t cookie,
+ struct uni_msg *msg, struct uni_all *u)
+{
+ struct sig *s;
+
+ if ((s = SIG_ALLOC()) != NULL) {
+ s->type = type;
+ s->sig = sig;
+ s->cookie = cookie;
+ s->msg = msg;
+ s->call = call;
+ s->party = party;
+ s->u = u;
+ TAILQ_INSERT_TAIL(&uni->delq, s, link);
+ }
+}
+
+/**************************************************************/
+
+void
+uniapi_uni_error(struct uni *uni, u_int32_t reason, u_int32_t cookie,
+ u_int32_t state)
+{
+ struct uni_msg *resp;
+ struct uniapi_error *err;
+
+ if (cookie == 0)
+ return;
+
+ resp = uni_msg_alloc(sizeof(struct uniapi_error));
+ err = uni_msg_wptr(resp, struct uniapi_error *);
+ resp->b_wptr += sizeof(struct uniapi_error);
+
+ err->reason = reason;
+ err->state = state;
+
+ uni->funcs->uni_output(uni, uni->arg, UNIAPI_ERROR, cookie, resp);
+}
+
+void
+uniapi_call_error(struct call *c, u_int32_t reason, u_int32_t cookie)
+{
+ uniapi_uni_error(c->uni, reason, cookie, callstates[c->cstate].ext);
+}
+void
+uniapi_party_error(struct party *p, u_int32_t reason, u_int32_t cookie)
+{
+ uniapi_uni_error(p->call->uni, reason, cookie,
+ callstates[p->call->cstate].ext);
+}
+
+/**************************************************************/
+void
+uni_status(struct uni *uni, void *arg)
+{
+ uni->funcs->status(uni, uni->arg, arg,
+ "working: %s\n", uni->working ? "yes" : "no");
+ uni->funcs->status(uni, uni->arg, arg,
+ "work queue: %sempty\n", TAILQ_EMPTY(&uni->workq)? "" : "not ");
+ uni->funcs->status(uni, uni->arg, arg,
+ "delayed work queue: %sempty\n",
+ TAILQ_EMPTY(&uni->delq)? "" : "not ");
+ uni->funcs->status(uni, uni->arg, arg,
+ "coordinator: %s\n", custat_names[uni->custat]);
+ uni->funcs->status(uni, uni->arg, arg,
+ "reset-start: %s\n", globstat_names[uni->glob_start]);
+ uni->funcs->status(uni, uni->arg, arg,
+ "reset-respond: %s\n", globstat_names[uni->glob_respond]);
+}
+
+void
+uni_undel(struct uni *uni, int (*filter)(struct sig *, void *), void *arg)
+{
+ struct sigqueue newq;
+ struct sig *s, *s1;
+
+ if (TAILQ_EMPTY(&uni->delq))
+ return;
+
+ TAILQ_INIT(&newq);
+
+ s = TAILQ_FIRST(&uni->delq);
+ while (s != NULL) {
+ s1 = TAILQ_NEXT(s, link);
+ if ((*filter)(s, arg)) {
+ TAILQ_REMOVE(&uni->delq, s, link);
+ TAILQ_INSERT_TAIL(&uni->workq, s, link);
+ }
+ s = s1;
+ }
+}
+
+void
+uni_delsig(struct uni *uni, u_int type, struct call *c, struct party *p)
+{
+ struct sig *s, *s1;
+
+ s = TAILQ_FIRST(&uni->workq);
+ while (s != NULL) {
+ s1 = TAILQ_NEXT(s, link);
+ if ((type == SIG_CALL && s->type == SIG_CALL &&
+ s->call == c) ||
+ (type == SIG_PARTY && s->type == SIG_PARTY &&
+ s->call == c && s->party == p)) {
+ TAILQ_REMOVE(&uni->workq, s, link);
+ if (s->msg)
+ uni_msg_destroy(s->msg);
+ if (s->u)
+ UNI_FREE(s->u);
+ SIG_FREE(s);
+ }
+ s = s1;
+ }
+
+ s = TAILQ_FIRST(&uni->delq);
+ while (s != NULL) {
+ s1 = TAILQ_NEXT(s, link);
+ if ((type == SIG_CALL && s->type == SIG_CALL &&
+ s->call == c) ||
+ (type == SIG_PARTY && s->type == SIG_PARTY &&
+ s->call == c && s->party == p)) {
+ TAILQ_REMOVE(&uni->delq, s, link);
+ if (s->msg)
+ uni_msg_destroy(s->msg);
+ if (s->u)
+ UNI_FREE(s->u);
+ SIG_FREE(s); \
+ }
+ s = s1;
+ }
+}
+
+/**************************************************************/
+
+void
+uni_get_config(const struct uni *uni, struct uni_config *config)
+{
+ config->proto = uni->proto;
+
+ config->popt = 0;
+ if (uni->cx.q2932)
+ config->popt |= UNIPROTO_GFP;
+
+ config->option = 0;
+ if (uni->cx.git_hard)
+ config->option |= UNIOPT_GIT_HARD;
+ if (uni->cx.bearer_hard)
+ config->option |= UNIOPT_BEARER_HARD;
+ if (uni->cx.cause_hard)
+ config->option |= UNIOPT_CAUSE_HARD;
+ if (uni->sb_tb)
+ config->popt |= UNIPROTO_SB_TB;
+
+ config->timer301 = uni->timer301;
+ config->timer303 = uni->timer303;
+ config->init303 = uni->init303;
+ config->timer308 = uni->timer308;
+ config->init308 = uni->init308;
+ config->timer309 = uni->timer309;
+ config->timer310 = uni->timer310;
+ config->timer313 = uni->timer313;
+ config->timer316 = uni->timer316;
+ config->init316 = uni->init316;
+ config->timer317 = uni->timer317;
+ config->timer322 = uni->timer322;
+ config->init322 = uni->init322;
+ config->timer397 = uni->timer397;
+ config->timer398 = uni->timer398;
+ config->timer399 = uni->timer399;
+}
+
+void
+uni_set_config(struct uni *uni, const struct uni_config *config,
+ u_int32_t *mask, u_int32_t *popt_mask, u_int32_t *opt_mask)
+{
+ int idle;
+
+ idle = TAILQ_EMPTY(&uni->calls) &&
+ TAILQ_EMPTY(&uni->workq) &&
+ TAILQ_EMPTY(&uni->delq);
+
+ if ((*mask & UNICFG_PROTO) && idle) {
+ switch (config->proto) {
+
+ case UNIPROTO_UNI40U:
+ case UNIPROTO_UNI40N:
+ /* case UNIPROTO_PNNI10: XXX */
+ uni->proto = config->proto;
+ *mask &= ~UNICFG_PROTO;
+ break;
+ }
+ }
+ if (*popt_mask & UNIPROTO_GFP) {
+ if (config->popt & UNIPROTO_GFP) {
+ uni->cx.q2932 = 1;
+ *popt_mask &= ~UNIPROTO_GFP;
+ } else {
+ if (!uni->cx.q2932 || idle) {
+ uni->cx.q2932 = 0;
+ *popt_mask &= ~UNIPROTO_GFP;
+ }
+ }
+ }
+ if (*popt_mask & UNIPROTO_SB_TB) {
+ uni->sb_tb = ((config->popt & UNIPROTO_SB_TB) != 0);
+ *popt_mask &= ~UNIPROTO_SB_TB;
+ }
+ if (*opt_mask & UNIOPT_GIT_HARD) {
+ uni->cx.git_hard = ((config->option & UNIOPT_GIT_HARD) != 0);
+ *opt_mask &= ~UNIOPT_GIT_HARD;
+ }
+ if (*opt_mask & UNIOPT_BEARER_HARD) {
+ uni->cx.bearer_hard = ((config->option & UNIOPT_BEARER_HARD) != 0);
+ *opt_mask &= ~UNIOPT_BEARER_HARD;
+ }
+ if (*opt_mask & UNIOPT_CAUSE_HARD) {
+ uni->cx.cause_hard = ((config->option & UNIOPT_CAUSE_HARD) != 0);
+ *opt_mask &= ~UNIOPT_CAUSE_HARD;
+ }
+
+#define SET_TIMER(NAME,name) \
+ if (*mask & UNICFG_##NAME) { \
+ uni->name = config->name; \
+ *mask &= ~UNICFG_##NAME; \
+ }
+
+ SET_TIMER(TIMER301, timer301);
+ SET_TIMER(TIMER303, timer303);
+ SET_TIMER(INIT303, init303);
+ SET_TIMER(TIMER308, timer308);
+ SET_TIMER(INIT308, init308);
+ SET_TIMER(TIMER309, timer309);
+ SET_TIMER(TIMER310, timer310);
+ SET_TIMER(TIMER313, timer313);
+ SET_TIMER(TIMER316, timer316);
+ SET_TIMER(INIT316, init316);
+ SET_TIMER(TIMER317, timer317);
+ SET_TIMER(TIMER322, timer322);
+ SET_TIMER(INIT322, init322);
+ SET_TIMER(TIMER397, timer397);
+ SET_TIMER(TIMER398, timer398);
+ SET_TIMER(TIMER399, timer399);
+
+#undef SET_TIMER
+}
+
+void
+uni_set_debug(struct uni *uni, enum uni_verb fac, u_int level)
+{
+ uni->debug[fac] = level;
+}
+
+u_int
+uni_get_debug(const struct uni *uni, enum uni_verb fac)
+{
+ return (uni->debug[fac]);
+}
+
+u_int
+uni_getcustate(const struct uni *uni)
+{
+ return (uni->custat);
+}
diff --git a/sys/contrib/ngatm/netnatm/sig/sig_verify.c b/sys/contrib/ngatm/netnatm/sig/sig_verify.c
new file mode 100644
index 0000000..fe9561b
--- /dev/null
+++ b/sys/contrib/ngatm/netnatm/sig/sig_verify.c
@@ -0,0 +1,442 @@
+/*
+ * Copyright (c) 2001-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/sig/sig_verify.c,v 1.16 2003/10/10 14:37:28 hbb Exp $
+ *
+ * Message verification with explicit action indicators.
+ */
+
+#include <netnatm/unimsg.h>
+#include <netnatm/saal/sscfudef.h>
+#include <netnatm/msg/unistruct.h>
+#include <netnatm/msg/unimsglib.h>
+#include <netnatm/sig/uni.h>
+
+#include <netnatm/sig/unipriv.h>
+#include <netnatm/sig/unimkmsg.h>
+
+void
+uni_mandate_ie(struct uni *uni, enum uni_ietype ie)
+{
+ struct uni_ierr *e;
+
+ FOREACH_ERR(e, uni)
+ if (e->ie == ie) {
+ e->man = 1;
+ return;
+ }
+ if (UNI_SAVE_IERR(&uni->cx, ie, UNI_IEACT_DEFAULT, UNI_IERR_MIS))
+ uni->cx.err[uni->cx.errcnt - 1].man = 1;
+}
+
+/*
+ * This special handling is required for ADD PARTY, PARTY ALERTING and
+ * ADD PARTY ACKNOWLEDGE by Q.2971 9.5.3.2.1.
+ * It means, that the EPREF should be handled as mandatory only if
+ * no other IEs have explicit action indicators.
+ */
+void
+uni_mandate_epref(struct uni *uni, struct uni_ie_epref *epref)
+{
+ struct uni_ierr *e;
+ int maxact;
+
+ if (!IE_ISPRESENT(*epref)) {
+ /*
+ * 9.5.3.2.1 -- missing endpoint reference
+ */
+
+ /*
+ * a) if any unrecognized or IE with error has a CLEAR
+ * action indicator, this takes precedence.
+ * b) if any unrecognized or IE with error has a
+ * discard message and report action indicator, this takes
+ * precedence.
+ * c) if any unrecognized or IE with error has a
+ * discard message action indicator, this takes
+ * precedence.
+ *
+ * In any of these cases we must remove the EPREF IE
+ * if it has CLEAR, otherwise the CLEAR would take over.
+ */
+ maxact = -1;
+ FOREACH_ERR(e, uni) {
+ if (e->ie == UNI_IE_EPREF)
+ continue;
+ if (e->act == UNI_IEACT_CLEAR)
+ maxact = UNI_IEACT_CLEAR;
+ else if (e->act == UNI_IEACT_MSG_REPORT) {
+ if (maxact == -1 && maxact != UNI_IEACT_CLEAR)
+ maxact = UNI_IEACT_MSG_REPORT;
+ } else if (e->act == UNI_IEACT_MSG_IGNORE) {
+ if (maxact == -1)
+ maxact = UNI_IEACT_MSG_IGNORE;
+ }
+ }
+
+ if (maxact != -1) {
+ /* ok, second pass to remove UNI_IE_EPREF */
+ FOREACH_ERR(e, uni)
+ if (e->ie == UNI_IE_EPREF) {
+ memmove(e, e + 1,
+ (uni->cx.errcnt - (e - uni->cx.err)
+ - 1) * sizeof(uni->cx.err[0]));
+ uni->cx.errcnt--;
+ break;
+ }
+ return;
+
+ }
+
+ /*
+ * d) if nothing of the above, the IE is mandatory
+ */
+ uni_mandate_ie(uni, UNI_IE_EPREF);
+ return;
+
+ }
+ if (IE_ISGOOD(*epref))
+ return;
+
+ /*
+ * It has an error obviously
+ * 9.5.3.2.2
+ *
+ * It turns out, that Q.2931 handling just does the right thing
+ * if we don't mandate the IE.
+ */
+ return;
+}
+
+/*
+ * Look, what to do with this message. We assume, that the message itself is
+ * recognized.
+ *
+ * This is rather complicated. We must use the information provided in the
+ * fields of the context, because IEs with length errors may not be set
+ * altogether.
+ */
+enum verify
+uni_verify(struct uni *uni, enum uni_msgact msgact)
+{
+ struct uni_ierr *e1;
+
+ if (uni->debug[UNI_FAC_VERIFY] >= 2) {
+ FOREACH_ERR(e1, uni) {
+ VERBOSE(uni, UNI_FAC_VERIFY, 2, "ie=%02x err=%u man=%d"
+ " act=%u", e1->ie, e1->err, e1->man, e1->act);
+ }
+ }
+
+ /*
+ * Look for missing mandatory IEs. The action indicator is ignored
+ * according to 5.6.7.1. If IEs are missing the action is to
+ * ignore the message and report status for all messages except
+ * RELEASE, RELEASE_COMPLETE and SETUP. Because we must differentiate
+ * this RAI from other RAIs in this case, use another return code.
+ * Note, that mandatory IEs with errors are not handled here.
+ */
+ FOREACH_ERR(e1, uni) {
+ if (e1->err == UNI_IERR_MIS) {
+ MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_MANDAT);
+ VERBOSE(uni, UNI_FAC_VERIFY, 1, "RAIM");
+ return (VFY_RAIM);
+ }
+ }
+
+ /*
+ * When any IE with error specifies a CLR action indicator, this
+ * takes precedence obviously. There are two cases here:
+ * unrecognized IEs and IEs with error. So we look through the
+ * error array twice and send only one STATUS. Unrecognized will
+ * take precedence.
+ *
+ * 5.7.2a)
+ */
+ FOREACH_ERR(e1, uni) {
+ if (e1->act == UNI_IEACT_CLEAR && e1->err == UNI_IERR_UNK) {
+ MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_IE_NIMPL);
+ VERBOSE(uni, UNI_FAC_VERIFY, 1, "CLR1");
+ return (VFY_CLR);
+ }
+ }
+
+ FOREACH_ERR(e1, uni) {
+ if (e1->act == UNI_IEACT_CLEAR &&
+ (e1->err == UNI_IERR_LEN || e1->err == UNI_IERR_BAD ||
+ e1->err == UNI_IERR_ACC)) {
+ MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_IE_INV);
+ VERBOSE(uni, UNI_FAC_VERIFY, 1, "CLR2");
+ return (VFY_CLR);
+ }
+ }
+
+ /*
+ * Now check, whether anybody wants to explicitly ignore the message
+ * and report status.
+ *
+ * 5.7.2a)
+ */
+ FOREACH_ERR(e1, uni) {
+ if (e1->act == UNI_IEACT_MSG_REPORT && e1->err == UNI_IERR_UNK) {
+ MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_IE_NIMPL);
+ VERBOSE(uni, UNI_FAC_VERIFY, 1, "RAI");
+ return (VFY_RAI);
+ }
+ }
+
+ FOREACH_ERR(e1, uni) {
+ if (e1->act == UNI_IEACT_MSG_REPORT &&
+ (e1->err == UNI_IERR_LEN || e1->err == UNI_IERR_BAD ||
+ e1->err == UNI_IERR_ACC)) {
+ MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_IE_INV);
+ VERBOSE(uni, UNI_FAC_VERIFY, 1, "RAI");
+ return (VFY_RAI);
+ }
+ }
+
+ /*
+ * Now look whether some IE wants to explicitely ignore the message
+ * without any report.
+ */
+ FOREACH_ERR(e1, uni) {
+ if (e1->act == UNI_IEACT_MSG_IGNORE) {
+ VERBOSE(uni, UNI_FAC_VERIFY, 1, "I1");
+ return (VFY_I);
+ }
+ }
+
+ /*
+ * At this point we have left only
+ * mandatory and non-mandatory IEs with error that want the IE to be
+ * ignored or ignored with report or defaulted.
+ * Because a mandatory IE with errors lead to
+ * the message beeing ignored, we make this of higher
+ * precedence, than the rest.
+ */
+ FOREACH_ERR(e1, uni) {
+ if (e1->man) {
+ MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_MANDAT);
+ VERBOSE(uni, UNI_FAC_VERIFY, 1, "RAI");
+ return (VFY_RAI);
+ }
+ }
+
+ /*
+ * Now look for ignoring the IE and reporting. This takes precedence
+ * over simply ignoring it. We also collect defaulted (non-mandatory)
+ * IEs.
+ *
+ * 5.7.2d) and 5.6.8.1
+ */
+ FOREACH_ERR(e1, uni) {
+ if ((e1->act == UNI_IEACT_DEFAULT ||
+ e1->act == UNI_IEACT_REPORT)
+ && e1->err != UNI_IERR_UNK) {
+ MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_IE_INV);
+ VERBOSE(uni, UNI_FAC_VERIFY, 1, "RAP");
+ return (VFY_RAP);
+ }
+ }
+
+ FOREACH_ERR(e1, uni) {
+ if ((e1->act == UNI_IEACT_DEFAULT ||
+ e1->act == UNI_IEACT_REPORT)
+ && e1->err == UNI_IERR_UNK) {
+ MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_IE_NIMPL);
+ VERBOSE(uni, UNI_FAC_VERIFY, 1, "RAPU");
+ return (VFY_RAPU);
+ }
+ }
+
+ /*
+ * This leaves us with IEs, that want to be ignored. Among these may
+ * be mandatory IEs. If we have an mandatory IEs here in the error
+ * array, then the message wil not contain enough information and
+ * must be handled according to 5.8 as either in 5.6.7.1 (this
+ * means, that mandatory IEs cannot really be ignored) or 5.7.1.
+ */
+ FOREACH_ERR(e1, uni) {
+ if (e1->man) {
+ MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_MANDAT);
+ if (msgact == UNI_MSGACT_CLEAR) {
+ VERBOSE(uni, UNI_FAC_VERIFY, 1, "CLR3");
+ return (VFY_CLR);
+ }
+ if (msgact == UNI_MSGACT_IGNORE) {
+ VERBOSE(uni, UNI_FAC_VERIFY, 1, "I2");
+ return (VFY_I);
+ }
+ VERBOSE(uni, UNI_FAC_VERIFY, 1, "RAI");
+ return (VFY_RAI);
+ }
+ }
+
+ /*
+ * Now only non-mandatory IEs are left, that want to be explicitely
+ * ignored.
+ */
+ if (uni->cx.errcnt != 0)
+ MK_IE_CAUSE(uni->cause, UNI_CAUSE_LOC_USER,
+ UNI_CAUSE_IE_INV);
+
+ VERBOSE(uni, UNI_FAC_VERIFY, 1, "OK");
+ return (VFY_OK);
+}
+
+/*
+ * Collect the IE identifiers for some of the known cause codes.
+ */
+void
+uni_vfy_collect_ies(struct uni *uni)
+{
+ struct uni_ierr *e;
+
+#define STUFF_IE(IE) \
+ uni->cause.u.ie.ie[uni->cause.u.ie.len++] = (IE); \
+ if (uni->cause.u.ie.len == UNI_CAUSE_IE_N) \
+ break;
+
+ uni->cause.u.ie.len = 0;
+ if (uni->cause.cause == UNI_CAUSE_MANDAT) {
+ FOREACH_ERR(e, uni) {
+ if (e->err == UNI_IERR_MIS || e->man != 0) {
+ STUFF_IE(e->ie);
+ }
+ }
+
+ } else if (uni->cause.cause == UNI_CAUSE_IE_NIMPL) {
+ FOREACH_ERR(e, uni) {
+ if (e->err == UNI_IERR_UNK) {
+ STUFF_IE(e->ie);
+ }
+ }
+
+ } else if (uni->cause.cause == UNI_CAUSE_IE_INV) {
+ FOREACH_ERR(e, uni) {
+ if (e->err == UNI_IERR_LEN ||
+ e->err == UNI_IERR_BAD ||
+ e->err == UNI_IERR_ACC) {
+ STUFF_IE(e->ie);
+ }
+ }
+ } else
+ return;
+
+ if (uni->cause.u.ie.len != 0)
+ uni->cause.h.present |= UNI_CAUSE_IE_P;
+}
+
+
+void
+uni_respond_status_verify(struct uni *uni, struct uni_cref *cref,
+ enum uni_callstate cs, struct uni_ie_epref *epref,
+ enum uni_epstate ps)
+{
+ struct uni_all *resp;
+
+ if ((resp = UNI_ALLOC()) == NULL)
+ return;
+
+ uni_vfy_collect_ies(uni);
+
+ MK_MSG_RESP(resp, UNI_STATUS, cref);
+ MK_IE_CALLSTATE(resp->u.status.callstate, cs);
+ resp->u.status.cause = uni->cause;
+ if (epref && IE_ISGOOD(*epref)) {
+ MK_IE_EPREF(resp->u.status.epref, epref->epref, !epref->flag);
+ MK_IE_EPSTATE(resp->u.status.epstate, ps);
+ }
+
+ uni_send_output(resp, uni);
+
+ UNI_FREE(resp);
+}
+
+/*
+ * Handling of Q.2971 9.5.8.1:
+ */
+void
+uni_vfy_remove_unknown(struct uni *uni)
+{
+ struct uni_ierr *e1, *e0;
+ int flag = 0;
+
+ FOREACH_ERR(e1, uni) {
+ if (e1->err == UNI_IERR_UNK) {
+ if (e1->act == UNI_IEACT_CLEAR ||
+ e1->act == UNI_IEACT_MSG_IGNORE ||
+ e1->act == UNI_IEACT_MSG_REPORT)
+ return;
+ if (e1->act == UNI_IEACT_REPORT ||
+ e1->act == UNI_IEACT_DEFAULT)
+ flag = 1;
+ }
+ }
+ if (flag)
+ return;
+ e0 = e1 = uni->cx.err;
+ while (e1 < uni->cx.err + uni->cx.errcnt) {
+ if (e1->err != UNI_IERR_UNK) {
+ if (e0 != e1)
+ *e0 = *e1;
+ e0++;
+ }
+ e1++;
+ }
+ uni->cx.errcnt = e0 - uni->cx.err;
+}
+
+/*
+ * Handling for ADD_PARTY_REJ and DROP_PARTY_ACK with bad cause
+ */
+void
+uni_vfy_remove_cause(struct uni *uni)
+{
+ struct uni_ierr *e1, *e0;
+
+ e0 = e1 = uni->cx.err;
+ while (e1 < uni->cx.err + uni->cx.errcnt) {
+ if (e1->ie != UNI_IE_CAUSE) {
+ if (e0 != e1)
+ *e0 = *e1;
+ e0++;
+ }
+ e1++;
+ }
+ uni->cx.errcnt = e0 - uni->cx.err;
+}
diff --git a/sys/contrib/ngatm/netnatm/sig/uni.h b/sys/contrib/ngatm/netnatm/sig/uni.h
new file mode 100644
index 0000000..9fa1943
--- /dev/null
+++ b/sys/contrib/ngatm/netnatm/sig/uni.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2001-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/sig/uni.h,v 1.3 2003/09/19 12:03:34 hbb Exp $
+ *
+ * Public UNI interface
+ */
+#ifndef _NETNATM_SIG_UNI_H_
+#define _NETNATM_SIG_UNI_H_
+
+#include <netnatm/sig/unidef.h>
+
+struct uni;
+
+/* functions to be supplied by the user */
+struct uni_funcs {
+ /* output to the upper layer */
+ void (*uni_output)(struct uni *, void *, enum uni_sig,
+ u_int32_t, struct uni_msg *);
+
+ /* output to the SAAL */
+ void (*saal_output)(struct uni *, void *, enum saal_sig,
+ struct uni_msg *);
+
+ /* verbosity */
+ void (*verbose)(struct uni *, void *, enum uni_verb,
+ const char *, ...) __printflike(4, 5);
+
+ /* function to 'print' status */
+ void (*status)(struct uni *, void *, void *,
+ const char *, ...) __printflike(4, 5);
+
+#ifndef _KERNEL
+ /* start a timer */
+ void *(*start_timer)(struct uni *, void *, u_int,
+ void (*)(void *), void *);
+
+ /* stop a timer */
+ void (*stop_timer)(struct uni *, void *, void *);
+#endif
+};
+
+/* create a UNI instance */
+struct uni *uni_create(void *, const struct uni_funcs *);
+
+/* destroy a UNI instance, free all resources */
+void uni_destroy(struct uni *);
+
+/* generate a status report */
+void uni_status(struct uni *, void *);
+
+/* get current instance configuration */
+void uni_get_config(const struct uni *, struct uni_config *);
+
+/* set new instance configuration */
+void uni_set_config(struct uni *, const struct uni_config *,
+ u_int32_t *, u_int32_t *, u_int32_t *);
+
+/* input from the SAAL to the instance */
+void uni_saal_input(struct uni *, enum saal_sig, struct uni_msg *);
+
+/* input from the upper layer to the instance */
+void uni_uni_input(struct uni *, enum uni_sig, u_int32_t, struct uni_msg *);
+
+/* do work on pending signals */
+void uni_work(struct uni *);
+
+/* set debuging level */
+void uni_set_debug(struct uni *, enum uni_verb, u_int level);
+u_int uni_get_debug(const struct uni *, enum uni_verb);
+
+/* reset a UNI instance */
+void uni_reset(struct uni *);
+
+/* states */
+u_int uni_getcustate(const struct uni *);
+
+/* return a reference to the coding/decoding context */
+struct unicx *uni_context(struct uni *);
+
+#endif
diff --git a/sys/contrib/ngatm/netnatm/sig/unidef.h b/sys/contrib/ngatm/netnatm/sig/unidef.h
new file mode 100644
index 0000000..a92bd18
--- /dev/null
+++ b/sys/contrib/ngatm/netnatm/sig/unidef.h
@@ -0,0 +1,474 @@
+/*
+ * 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/sig/unidef.h,v 1.6 2003/09/19 12:03:34 hbb Exp $
+ *
+ * UNI public definitions.
+ */
+#ifndef _ATM_SIG_UNIDEF_H_
+#define _ATM_SIG_UNIDEF_H_
+
+/*
+ * Debug facilities
+ */
+#define UNI_DEBUG_FACILITIES \
+ UNI_DEBUG_DEFINE(TIMEOUT) \
+ UNI_DEBUG_DEFINE(RESTART) \
+ UNI_DEBUG_DEFINE(SAAL) \
+ UNI_DEBUG_DEFINE(PARSE) \
+ UNI_DEBUG_DEFINE(CALL) \
+ UNI_DEBUG_DEFINE(WARN) \
+ UNI_DEBUG_DEFINE(COORD) \
+ UNI_DEBUG_DEFINE(API) \
+ UNI_DEBUG_DEFINE(MSG) \
+ UNI_DEBUG_DEFINE(ERR) \
+ UNI_DEBUG_DEFINE(VERIFY) \
+
+enum uni_verb {
+#define UNI_DEBUG_DEFINE(D) UNI_FAC_##D,
+ UNI_DEBUG_FACILITIES
+#undef UNI_DEBUG_DEFINE
+
+ UNI_MAXFACILITY,
+};
+
+/*
+ * Default timer values and repeat counts
+ */
+#define UNI_T301_DEFAULT 180000
+#define UNI_T303_DEFAULT 4000
+#define UNI_T303_CNT_DEFAULT 2
+#define UNI_T308_DEFAULT 30000
+#define UNI_T308_CNT_DEFAULT 2
+#define UNI_T309_DEFAULT 10000
+#define UNI_T310U_DEFAULT 30000
+#define UNI_T310N_DEFAULT 10000
+#define UNI_T313_DEFAULT 4000
+#define UNI_T316_DEFAULT 120000
+#define UNI_T316_CNT_DEFAULT 2
+#define UNI_T317_DEFAULT 90000
+#define UNI_T322_DEFAULT 4000
+#define UNI_T322_CNT_DEFAULT 2
+#define UNI_T397_DEFAULT UNI_T301_DEFAULT
+#define UNI_T398_DEFAULT 4000
+#define UNI_T399U_DEFAULT (UNI_T303_DEFAULT + UNI_T310U_DEFAULT)
+#define UNI_T399N_DEFAULT (UNI_T303_DEFAULT + UNI_T310N_DEFAULT)
+
+/*
+ * Protocol support
+ */
+enum uni_proto {
+ UNIPROTO_UNI40U, /* UNI4.0 user side */
+ UNIPROTO_UNI40N, /* UNI4.0 network side */
+ UNIPROTO_PNNI10, /* PNNI1.0 */
+};
+enum uni_popt {
+ UNIPROTO_GFP = 0x0001, /* enable GFP */
+ UNIPROTO_SB_TB = 0x0002, /* Coincident Sb-Tb/Tb */
+
+ UNIPROTO_ALLMASK = 0x0003,
+};
+
+/*
+ * Other options
+ */
+enum uni_option {
+ UNIOPT_GIT_HARD = 0x0001, /* harder check of GIT IE */
+ UNIOPT_BEARER_HARD = 0x0002, /* harder check of BEARER IE */
+ UNIOPT_CAUSE_HARD = 0x0004, /* harder check of CAUSE IE */
+
+ UNIOPT_ALLMASK = 0x0007,
+};
+
+/*
+ * UNI configuration
+ */
+struct uni_config {
+ u_int32_t proto; /* which protocol */
+ u_int32_t popt; /* protocol option */
+ u_int32_t option; /* other options */
+ u_int32_t timer301; /* T301 */
+ u_int32_t timer303; /* T303 */
+ u_int32_t init303; /* T303 retransmission count */
+ u_int32_t timer308; /* T308 */
+ u_int32_t init308; /* T308 retransmission count */
+ u_int32_t timer309; /* T309 */
+ u_int32_t timer310; /* T310 */
+ u_int32_t timer313; /* T313 */
+ u_int32_t timer316; /* T316 */
+ u_int32_t init316; /* T316 retransmission count */
+ u_int32_t timer317; /* T317 */
+ u_int32_t timer322; /* T322 */
+ u_int32_t init322; /* T322 retransmission count */
+ u_int32_t timer397; /* T397 */
+ u_int32_t timer398; /* T398 */
+ u_int32_t timer399; /* T399 */
+};
+enum uni_config_mask {
+ UNICFG_PROTO = 0x00000001,
+ UNICFG_TIMER301 = 0x00000002,
+ UNICFG_TIMER303 = 0x00000004,
+ UNICFG_INIT303 = 0x00000008,
+ UNICFG_TIMER308 = 0x00000010,
+ UNICFG_INIT308 = 0x00000020,
+ UNICFG_TIMER309 = 0x00000040,
+ UNICFG_TIMER310 = 0x00000080,
+ UNICFG_TIMER313 = 0x00000100,
+ UNICFG_TIMER316 = 0x00000200,
+ UNICFG_INIT316 = 0x00000400,
+ UNICFG_TIMER317 = 0x00000800,
+ UNICFG_TIMER322 = 0x00001000,
+ UNICFG_INIT322 = 0x00002000,
+ UNICFG_TIMER397 = 0x00004000,
+ UNICFG_TIMER398 = 0x00008000,
+ UNICFG_TIMER399 = 0x00010000,
+
+ UNICFG_ALLMASK = 0x0001ffff,
+};
+
+/*
+ * API signals
+ */
+enum uni_sig {
+ UNIAPI_ERROR = 0, /* UNI -> API */
+
+ UNIAPI_CALL_CREATED = 1, /* UNI -> API */
+ UNIAPI_CALL_DESTROYED = 2, /* UNI -> API */
+ UNIAPI_PARTY_CREATED = 3, /* UNI -> API */
+ UNIAPI_PARTY_DESTROYED = 4, /* UNI -> API */
+
+ UNIAPI_LINK_ESTABLISH_request = 5, /* API -> UNI */
+ UNIAPI_LINK_ESTABLISH_confirm = 6, /* UNI -> API */
+ UNIAPI_LINK_RELEASE_request = 7, /* API -> UNI */
+ UNIAPI_LINK_RELEASE_confirm = 8, /* UNI -> API */
+
+ UNIAPI_RESET_request = 9, /* API -> UNI */
+ UNIAPI_RESET_confirm = 10, /* UNI -> API */
+ UNIAPI_RESET_indication = 11, /* UNI -> API */
+ UNIAPI_RESET_ERROR_indication = 12, /* UNI -> API */
+ UNIAPI_RESET_response = 13, /* API -> UNI */
+ UNIAPI_RESET_ERROR_response = 14, /* API -> UNI */
+ UNIAPI_RESET_STATUS_indication = 15, /* UNI -> API */
+
+ UNIAPI_SETUP_request = 16, /* API -> UNI */
+ UNIAPI_SETUP_indication = 17, /* UNI -> API */
+ UNIAPI_SETUP_response = 18, /* API -> UNI */
+ UNIAPI_SETUP_confirm = 19, /* UNI -> API */
+ UNIAPI_SETUP_COMPLETE_indication= 20, /* U-UNI -> API */
+ UNIAPI_SETUP_COMPLETE_request = 46, /* API -> N-UNI */
+ UNIAPI_ALERTING_request = 21, /* API -> UNI */
+ UNIAPI_ALERTING_indication = 22, /* UNI -> API */
+ UNIAPI_PROCEEDING_request = 23, /* API -> UNI */
+ UNIAPI_PROCEEDING_indication = 24, /* UNI -> API */
+ UNIAPI_RELEASE_request = 25, /* API -> UNI */
+ UNIAPI_RELEASE_indication = 26, /* UNI -> API */
+ UNIAPI_RELEASE_response = 27, /* API -> UNI */
+ UNIAPI_RELEASE_confirm = 28, /* UNI -> API */
+ UNIAPI_NOTIFY_request = 29, /* API -> UNI */
+ UNIAPI_NOTIFY_indication = 30, /* UNI -> API */
+ UNIAPI_STATUS_indication = 31, /* UNI -> API */
+ UNIAPI_STATUS_ENQUIRY_request = 32, /* API -> UNI */
+
+ UNIAPI_ADD_PARTY_request = 33, /* API -> UNI */
+ UNIAPI_ADD_PARTY_indication = 34, /* UNI -> API */
+ UNIAPI_PARTY_ALERTING_request = 35, /* API -> UNI */
+ UNIAPI_PARTY_ALERTING_indication= 36, /* UNI -> API */
+ UNIAPI_ADD_PARTY_ACK_request = 37, /* API -> UNI */
+ UNIAPI_ADD_PARTY_ACK_indication = 38, /* UNI -> API */
+ UNIAPI_ADD_PARTY_REJ_request = 39, /* API -> UNI */
+ UNIAPI_ADD_PARTY_REJ_indication = 40, /* UNI -> API */
+ UNIAPI_DROP_PARTY_request = 41, /* API -> UNI */
+ UNIAPI_DROP_PARTY_indication = 42, /* UNI -> API */
+ UNIAPI_DROP_PARTY_ACK_request = 43, /* API -> UNI */
+ UNIAPI_DROP_PARTY_ACK_indication= 44, /* UNI -> API */
+
+ UNIAPI_ABORT_CALL_request = 45, /* API -> UNI */
+
+ UNIAPI_MAXSIG = 47
+};
+
+struct uniapi_error {
+ u_int32_t reason;
+ u_int32_t state;
+};
+/* keep this in sync with atmapi.h:enum atmerr */
+
+#define UNIAPI_DEF_ERRORS(MACRO) \
+ MACRO(OK, 0, "no error") \
+ MACRO(ERROR_BAD_SIGNAL, 1, "unknown signal") \
+ MACRO(ERROR_BADCU, 2, "signal in bad co-ordinator state") \
+ MACRO(ERROR_BAD_CALLSTATE, 3, "signal in bad call state") \
+ MACRO(ERROR_BAD_EPSTATE, 4, "signal in bad endpoint state") \
+ MACRO(ERROR_BAD_ARG, 5, "bad argument") \
+ MACRO(ERROR_BAD_CALL, 6, "unknown call reference") \
+ MACRO(ERROR_BAD_PARTY, 7, "unknown party") \
+ MACRO(ERROR_BAD_CTYPE, 8, "bad type of call for signal") \
+ MACRO(ERROR_BAD_IE, 9, "bad information element") \
+ MACRO(ERROR_EPREF_INUSE, 10, "endpoint reference already in use") \
+ MACRO(ERROR_MISSING_IE, 11, "missing information element") \
+ MACRO(ERROR_ENCODING, 12, "error during message encoding") \
+ MACRO(ERROR_NOMEM, 13, "out of memory") \
+ MACRO(ERROR_BUSY, 14, "status enquiry busy")
+
+enum {
+#define DEF(NAME, VAL, STR) UNIAPI_##NAME = VAL,
+UNIAPI_DEF_ERRORS(DEF)
+#undef DEF
+};
+
+struct uniapi_call_created {
+ struct uni_cref cref;
+};
+struct uniapi_call_destroyed {
+ struct uni_cref cref;
+};
+struct uniapi_party_created {
+ struct uni_cref cref;
+ struct uni_ie_epref epref;
+};
+struct uniapi_party_destroyed {
+ struct uni_cref cref;
+ struct uni_ie_epref epref;
+};
+struct uniapi_abort_call_request {
+ struct uni_cref cref;
+};
+
+struct uniapi_reset_request {
+ struct uni_ie_restart restart;
+ struct uni_ie_connid connid;
+};
+
+struct uniapi_reset_confirm {
+ struct uni_ie_restart restart;
+ struct uni_ie_connid connid;
+};
+
+struct uniapi_reset_indication {
+ struct uni_ie_restart restart;
+ struct uni_ie_connid connid;
+
+};
+struct uniapi_reset_error_indication {
+ u_int32_t source; /* 0 - start, 1 - response */
+ u_int32_t reason;
+};
+
+#define UNIAPI_DEF_RESET_ERRORS(MACRO) \
+ MACRO(UNIAPI_RESET_ERROR_NO_CONFIRM, 0, \
+ "no confirmation") \
+ MACRO(UNIAPI_RESET_ERROR_NO_RESPONSE, 1, \
+ "no response") \
+ MACRO(UNIAPI_RESET_ERROR_PEER_INCOMP_STATE, 2, \
+ "incompatible state")
+enum {
+#define DEF(NAME, VALUE, STR) NAME = VALUE,
+UNIAPI_DEF_RESET_ERRORS(DEF)
+#undef DEF
+};
+
+struct uniapi_reset_response {
+ struct uni_ie_restart restart;
+ struct uni_ie_connid connid;
+};
+
+struct uniapi_reset_error_response {
+ struct uni_ie_cause cause;
+};
+
+struct uniapi_reset_status_indication {
+ struct uni_cref cref; /* STATUS message CREF */
+ struct uni_ie_callstate callstate;
+ struct uni_ie_cause cause;
+};
+
+struct uniapi_setup_request {
+ struct uni_setup setup;
+};
+struct uniapi_setup_indication {
+ struct uni_setup setup;
+};
+struct uniapi_setup_response {
+ struct uni_connect connect;
+};
+struct uniapi_setup_confirm {
+ struct uni_connect connect;
+};
+struct uniapi_setup_complete_indication {
+ struct uni_connect_ack connect_ack;
+};
+struct uniapi_setup_complete_request {
+ struct uni_connect_ack connect_ack;
+};
+
+struct uniapi_alerting_request {
+ struct uni_alerting alerting;
+};
+
+struct uniapi_alerting_indication {
+ struct uni_alerting alerting;
+};
+
+struct uniapi_proceeding_request {
+ struct uni_call_proc call_proc;
+};
+
+struct uniapi_proceeding_indication {
+ struct uni_call_proc call_proc;
+};
+
+
+struct uniapi_release_request {
+ struct uni_release release;
+};
+struct uniapi_release_indication {
+ struct uni_release release;
+};
+struct uniapi_release_response {
+ struct uni_release_compl release_compl;
+};
+/*
+ * A release confirm can come from a RELEASE COMPLETE or a RELEASE.
+ * Because the IEs in a RELEASE COMPLETE are a subset of a RELEASE,
+ * use the RELEASE here.
+ */
+struct uniapi_release_confirm {
+ struct uni_release release;
+};
+
+struct uniapi_notify_request {
+ struct uni_notify notify;
+};
+struct uniapi_notify_indication {
+ struct uni_notify notify;
+};
+
+struct uniapi_status_indication {
+ struct uni_cref cref;
+ enum uni_callstate my_state;
+ enum uni_cause my_cause;
+ struct uni_ie_callstate his_state;
+ struct uni_ie_cause his_cause;
+ struct uni_ie_epref epref;
+ struct uni_ie_epstate epstate;
+};
+struct uniapi_status_enquiry_request {
+ struct uni_cref cref;
+ struct uni_ie_epref epref;
+};
+
+struct uniapi_add_party_request {
+ struct uni_add_party add;
+};
+struct uniapi_add_party_indication {
+ struct uni_add_party add;
+};
+
+struct uniapi_party_alerting_request {
+ struct uni_party_alerting alert;
+};
+struct uniapi_party_alerting_indication {
+ struct uni_party_alerting alert;
+};
+
+struct uniapi_add_party_ack_request {
+ struct uni_add_party_ack ack;
+};
+struct uniapi_add_party_ack_indication {
+ struct uni_add_party_ack ack;
+};
+struct uniapi_add_party_rej_request {
+ struct uni_add_party_rej rej;
+};
+struct uniapi_add_party_rej_indication {
+ struct uni_add_party_rej rej;
+};
+
+struct uniapi_drop_party_request {
+ struct uni_drop_party drop;
+};
+struct uniapi_drop_party_indication {
+ struct uni_drop_party drop;
+ struct uni_ie_cause my_cause;
+};
+
+struct uniapi_drop_party_ack_request {
+ struct uni_drop_party_ack ack;
+};
+struct uniapi_drop_party_ack_indication {
+ struct uni_drop_party drop;
+ struct uni_ie_crankback crankback;
+};
+
+union uniapi_all {
+ struct uniapi_error error;
+ struct uniapi_call_created call_created;
+ struct uniapi_call_destroyed call_destroyed;
+ struct uniapi_party_created party_created;
+ struct uniapi_party_destroyed party_destroyed;
+ struct uniapi_abort_call_request abort_call_request;
+ struct uniapi_reset_request reset_request;
+ struct uniapi_reset_confirm reset_confirm;
+ struct uniapi_reset_indication reset_indication;
+ struct uniapi_reset_error_indication reset_error_indication;
+ struct uniapi_reset_response reset_response;
+ struct uniapi_reset_error_response reset_error_response;
+ struct uniapi_reset_status_indication reset_status_indication;
+ struct uniapi_setup_request setup_request;
+ struct uniapi_setup_indication setup_indication;
+ struct uniapi_setup_response setup_response;
+ struct uniapi_setup_confirm setup_confirm;
+ struct uniapi_setup_complete_indication setup_complete_indication;
+ struct uniapi_setup_complete_request setup_complete_request;
+ struct uniapi_alerting_request alerting_request;
+ struct uniapi_alerting_indication alerting_indication;
+ struct uniapi_proceeding_request proceeding_request;
+ struct uniapi_proceeding_indication proceeding_indication;
+ struct uniapi_release_request release_request;
+ struct uniapi_release_indication release_indication;
+ struct uniapi_release_response release_response;
+ struct uniapi_release_confirm release_confirm;
+ struct uniapi_notify_request notify_request;
+ struct uniapi_notify_indication notify_indication;
+ struct uniapi_status_indication status_indication;
+ struct uniapi_status_enquiry_request status_enquiry_request;
+ struct uniapi_add_party_request add_party_request;
+ struct uniapi_add_party_indication add_party_indication;
+ struct uniapi_party_alerting_request party_alerting_request;
+ struct uniapi_party_alerting_indication party_alerting_indication;
+ struct uniapi_add_party_ack_request add_party_ack_request;
+ struct uniapi_add_party_ack_indication add_party_ack_indication;
+ struct uniapi_add_party_rej_request add_party_rej_request;
+ struct uniapi_add_party_rej_indication add_party_rej_indication;
+ struct uniapi_drop_party_request drop_party_request;
+ struct uniapi_drop_party_indication drop_party_indication;
+ struct uniapi_drop_party_ack_request drop_party_ack_request;
+ struct uniapi_drop_party_ack_indication drop_party_ack_indication;
+};
+
+#endif
diff --git a/sys/contrib/ngatm/netnatm/sig/unimkmsg.h b/sys/contrib/ngatm/netnatm/sig/unimkmsg.h
new file mode 100644
index 0000000..8523825
--- /dev/null
+++ b/sys/contrib/ngatm/netnatm/sig/unimkmsg.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2001-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/sig/unimkmsg.h,v 1.4 2003/09/19 12:03:34 hbb Exp $
+ *
+ * Macros to make messages.
+ */
+
+#define MK_MSG_ORIG(MSG,TYPE,CREF,FLAG) \
+ do { \
+ (MSG)->mtype = (TYPE); \
+ (MSG)->u.hdr.cref.cref = (CREF); \
+ (MSG)->u.hdr.cref.flag = (FLAG); \
+ (MSG)->u.hdr.act = UNI_MSGACT_DEFAULT; \
+ } while(0)
+
+#define MK_MSG_RESP(MSG,TYPE,CREF) \
+ do { \
+ (MSG)->mtype = (TYPE); \
+ (MSG)->u.hdr.cref.cref = (CREF)->cref; \
+ (MSG)->u.hdr.cref.flag = !(CREF)->flag; \
+ (MSG)->u.hdr.act = UNI_MSGACT_DEFAULT; \
+ } while(0)
+
+#define MK_IE_CALLSTATE(IE,CS) \
+ do { \
+ (IE).h.present = 0; \
+ IE_SETPRESENT(IE); \
+ (IE).h.coding = UNI_CODING_ITU; \
+ (IE).h.act = UNI_IEACT_DEFAULT; \
+ (IE).state = CS; \
+ } while(0)
+
+#define MK_IE_EPREF(IE,EPREF,FLAG) \
+ do { \
+ (IE).h.present = 0; \
+ IE_SETPRESENT(IE); \
+ (IE).h.coding = UNI_CODING_ITU; \
+ (IE).h.act = UNI_IEACT_DEFAULT; \
+ (IE).epref = EPREF; \
+ (IE).flag = FLAG; \
+ } while(0)
+
+#define MK_IE_EPSTATE(IE,STATE) \
+ do { \
+ (IE).h.present = 0; \
+ IE_SETPRESENT(IE); \
+ (IE).h.coding = UNI_CODING_ITU; \
+ (IE).h.act = UNI_IEACT_DEFAULT; \
+ (IE).state = STATE; \
+ } while(0)
+
+#define MK_IE_CAUSE(IE,LOC,CAUSE) \
+ do { \
+ (IE).h.present = 0; \
+ IE_SETPRESENT(IE); \
+ (IE).h.coding = UNI_CODING_ITU; \
+ (IE).h.act = UNI_IEACT_DEFAULT; \
+ (IE).loc = LOC; \
+ (IE).cause = CAUSE; \
+ } while(0)
+
+#define ADD_CAUSE_MTYPE(IE,MTYPE) \
+ do { \
+ (IE).h.present |= UNI_CAUSE_MTYPE_P; \
+ (IE).u.mtype = MTYPE; \
+ } while(0)
+
+#define ADD_CAUSE_CHANNID(IE,VPI,VCI) \
+ do { \
+ (IE).h.present |= UNI_CAUSE_VPCI_P; \
+ (IE).u.vpci.vpci = VPI; \
+ (IE).u.vpci.vci = VCI; \
+ } while(0)
+
+#define ADD_CAUSE_TIMER(IE,TIMER) \
+ do { \
+ (IE).h.present |= UNI_CAUSE_TIMER_P; \
+ (IE).u.timer[0] = (TIMER)[0]; \
+ (IE).u.timer[1] = (TIMER)[1]; \
+ (IE).u.timer[2] = (TIMER)[2]; \
+ } while(0)
+
+/************************************************************/
+
+#define COPY_FROM_RELEASE_COMPL(U,DEST) \
+ do { \
+ u_int _i, _j; \
+ \
+ for(_i = _j = 0; _i < 2; _i++) \
+ if(IE_ISGOOD((U)->u.release_compl.cause[_i])) \
+ (DEST)->cause[_j++] = \
+ (U)->u.release_compl.cause[_i]; \
+ for(_i = _j = 0; _i < UNI_NUM_IE_GIT; _i++) \
+ if(IE_ISGOOD((U)->u.release_compl.git[_i])) \
+ (DEST)->git[_j++] = \
+ (U)->u.release_compl.git[_i]; \
+ if(IE_ISGOOD((U)->u.release_compl.uu)) \
+ (DEST)->uu = (U)->u.release_compl.uu; \
+ if(IE_ISGOOD((U)->u.release_compl.crankback)) \
+ (DEST)->crankback = (U)->u.release_compl.crankback; \
+ } while(0)
+
+#define COPY_FROM_DROP_ACK(U,DEST) \
+ do { \
+ u_int _i, _j; \
+ \
+ if(IE_ISGOOD((U)->u.drop_party_ack.epref)) \
+ (DEST)->epref = (U)->u.drop_party_ack.epref; \
+ if(IE_ISGOOD((U)->u.drop_party_ack.cause)) \
+ (DEST)->cause = (U)->u.drop_party_ack.cause; \
+ if(IE_ISGOOD((U)->u.drop_party_ack.uu)) \
+ (DEST)->uu = (U)->u.drop_party_ack.uu; \
+ for(_i = _j = 0; _i < UNI_NUM_IE_GIT; _i++) \
+ if(IE_ISGOOD((U)->u.drop_party_ack.git[_i])) \
+ (DEST)->git[_j++] = \
+ (U)->u.drop_party_ack.git[_i]; \
+ } while(0)
+
+#define COPY_FROM_ADD_REJ(U,DEST) \
+ do { \
+ u_int _i, _j; \
+ \
+ if(IE_ISGOOD((U)->u.add_party_rej.epref)) \
+ (DEST)->epref = (U)->u.add_party_rej.epref; \
+ if(IE_ISGOOD((U)->u.add_party_rej.cause)) \
+ (DEST)->cause = (U)->u.add_party_rej.cause; \
+ if(IE_ISGOOD((U)->u.add_party_rej.uu)) \
+ (DEST)->uu = (U)->u.add_party_rej.uu; \
+ for(_i = _j = 0; _i < UNI_NUM_IE_GIT; _i++) \
+ if(IE_ISGOOD((U)->u.add_party_rej.git[_i])) \
+ (DEST)->git[_j++] = \
+ (U)->u.add_party_rej.git[_i]; \
+ } while(0)
diff --git a/sys/contrib/ngatm/netnatm/sig/unipriv.h b/sys/contrib/ngatm/netnatm/sig/unipriv.h
new file mode 100644
index 0000000..7b4a0d7
--- /dev/null
+++ b/sys/contrib/ngatm/netnatm/sig/unipriv.h
@@ -0,0 +1,544 @@
+/*
+ * 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/sig/unipriv.h,v 1.5 2003/09/24 10:27:50 hbb Exp $
+ *
+ * Private UNI stuff.
+ */
+#ifndef unipriv_h
+#define unipriv_h
+
+#ifdef _KERNEL
+#ifdef __FreeBSD__
+#include <netgraph/atm/uni/ng_uni_cust.h>
+#endif
+#else
+#include "unicust.h"
+#endif
+
+struct call;
+struct party;
+
+enum cu_stat {
+ CU_STAT0, /* AAL connection released */
+ CU_STAT1, /* awaiting establish */
+ CU_STAT2, /* awaiting release */
+ CU_STAT3, /* AAL connection established */
+};
+
+/*
+ * Internal Signals
+ */
+#define DEF_COORD_SIGS \
+ DEF_PRIV_SIG(O_SAAL_ESTABLISH_indication, SAAL) \
+ DEF_PRIV_SIG(O_SAAL_ESTABLISH_confirm, SAAL) \
+ DEF_PRIV_SIG(O_SAAL_RELEASE_indication, SAAL) \
+ DEF_PRIV_SIG(O_SAAL_RELEASE_confirm, SAAL) \
+ DEF_PRIV_SIG(O_SAAL_DATA_indication, SAAL) \
+ DEF_PRIV_SIG(O_SAAL_UDATA_indication, SAAL) \
+ DEF_PRIV_SIG(O_T309, Coord) \
+ DEF_PRIV_SIG(O_DATA, Coord) \
+ DEF_PRIV_SIG(O_LINK_ESTABLISH_request, API) \
+ DEF_PRIV_SIG(O_LINK_RELEASE_request, API) \
+ DEF_PRIV_SIG(O_RESET_request, API) \
+ DEF_PRIV_SIG(O_RESET_response, API) \
+ DEF_PRIV_SIG(O_RESET_ERROR_response, API) \
+ DEF_PRIV_SIG(O_SETUP_request, API) \
+ DEF_PRIV_SIG(O_SETUP_response, API) \
+ DEF_PRIV_SIG(O_SETUP_COMPLETE_request, API) \
+ DEF_PRIV_SIG(O_PROCEEDING_request, API) \
+ DEF_PRIV_SIG(O_ALERTING_request, API) \
+ DEF_PRIV_SIG(O_RELEASE_request, API) \
+ DEF_PRIV_SIG(O_RELEASE_response, API) \
+ DEF_PRIV_SIG(O_NOTIFY_request, API) \
+ DEF_PRIV_SIG(O_STATUS_ENQUIRY_request, API) \
+ DEF_PRIV_SIG(O_ADD_PARTY_request, API) \
+ DEF_PRIV_SIG(O_PARTY_ALERTING_request, API) \
+ DEF_PRIV_SIG(O_ADD_PARTY_ACK_request, API) \
+ DEF_PRIV_SIG(O_ADD_PARTY_REJ_request, API) \
+ DEF_PRIV_SIG(O_DROP_PARTY_request, API) \
+ DEF_PRIV_SIG(O_DROP_PARTY_ACK_request, API) \
+ DEF_PRIV_SIG(O_ABORT_CALL_request, API) \
+ DEF_PRIV_SIG(O_CALL_DESTROYED, CallControl) \
+ DEF_PRIV_SIG(O_RESET_indication, ResetRespond) \
+ DEF_PRIV_SIG(O_END, Coord)
+
+#define DEF_RESPOND_SIGS \
+ DEF_PRIV_SIG(R_RESTART, Coord) \
+ DEF_PRIV_SIG(R_STATUS, Coord) \
+ DEF_PRIV_SIG(R_RESET_response, Coord) \
+ DEF_PRIV_SIG(R_RESET_ERROR_response, Coord) \
+ DEF_PRIV_SIG(R_T317, ResetRespond) \
+ DEF_PRIV_SIG(R_END, ResetRespond)
+
+#define DEF_START_SIGS \
+ DEF_PRIV_SIG(S_RESTART_ACK, Coord) \
+ DEF_PRIV_SIG(S_STATUS, Coord) \
+ DEF_PRIV_SIG(S_RESET_request, Coord) \
+ DEF_PRIV_SIG(S_T316, ResetStart) \
+ DEF_PRIV_SIG(S_END, ResetStart)
+
+#define DEF_CALL_SIGS \
+ DEF_PRIV_SIG(C_LINK_ESTABLISH_confirm, Coord) \
+ DEF_PRIV_SIG(C_LINK_ESTABLISH_indication, Coord) \
+ DEF_PRIV_SIG(C_LINK_ESTABLISH_ERROR_indication,Coord) \
+ DEF_PRIV_SIG(C_LINK_RELEASE_indication, Coord) \
+ DEF_PRIV_SIG(C_SETUP_request, Coord) \
+ DEF_PRIV_SIG(C_SETUP_response, Coord) \
+ DEF_PRIV_SIG(C_SETUP_COMPLETE_request, Coord) \
+ DEF_PRIV_SIG(C_PROCEEDING_request, Coord) \
+ DEF_PRIV_SIG(C_ALERTING_request, Coord) \
+ DEF_PRIV_SIG(C_RELEASE_request, Coord) \
+ DEF_PRIV_SIG(C_RELEASE_response, Coord) \
+ DEF_PRIV_SIG(C_NOTIFY_request, Coord) \
+ DEF_PRIV_SIG(C_STATUS_ENQUIRY_request, Coord) \
+ DEF_PRIV_SIG(C_ADD_PARTY_request, Coord) \
+ DEF_PRIV_SIG(C_PARTY_ALERTING_request, Coord) \
+ DEF_PRIV_SIG(C_ADD_PARTY_ACK_request, Coord) \
+ DEF_PRIV_SIG(C_ADD_PARTY_REJ_request, Coord) \
+ DEF_PRIV_SIG(C_DROP_PARTY_request, Coord) \
+ DEF_PRIV_SIG(C_DROP_PARTY_ACK_request, Coord) \
+ DEF_PRIV_SIG(C_ABORT_CALL_request, Coord) \
+ DEF_PRIV_SIG(C_UNKNOWN, Coord) \
+ DEF_PRIV_SIG(C_SETUP, Coord) \
+ DEF_PRIV_SIG(C_CALL_PROC, Coord) \
+ DEF_PRIV_SIG(C_ALERTING, Coord) \
+ DEF_PRIV_SIG(C_CONNECT, Coord) \
+ DEF_PRIV_SIG(C_CONNECT_ACK, Coord) \
+ DEF_PRIV_SIG(C_RELEASE, Coord) \
+ DEF_PRIV_SIG(C_RELEASE_COMPL, Coord) \
+ DEF_PRIV_SIG(C_COBISETUP, Coord) \
+ DEF_PRIV_SIG(C_NOTIFY, Coord) \
+ DEF_PRIV_SIG(C_STATUS, Coord) \
+ DEF_PRIV_SIG(C_STATUS_ENQ, Coord) \
+ DEF_PRIV_SIG(C_ADD_PARTY, Coord) \
+ DEF_PRIV_SIG(C_PARTY_ALERTING, Coord) \
+ DEF_PRIV_SIG(C_ADD_PARTY_ACK, Coord) \
+ DEF_PRIV_SIG(C_ADD_PARTY_REJ, Coord) \
+ DEF_PRIV_SIG(C_DROP_PARTY, Coord) \
+ DEF_PRIV_SIG(C_DROP_PARTY_ACK, Coord) \
+ DEF_PRIV_SIG(C_CALL_DELETE, CallControl) \
+ DEF_PRIV_SIG(C_T301, CallControl) \
+ DEF_PRIV_SIG(C_T303, CallControl) \
+ DEF_PRIV_SIG(C_T308, CallControl) \
+ DEF_PRIV_SIG(C_T310, CallControl) \
+ DEF_PRIV_SIG(C_T313, CallControl) \
+ DEF_PRIV_SIG(C_T322, CallControl) \
+ DEF_PRIV_SIG(C_DROP_PARTY_indication, PartyControl) \
+ DEF_PRIV_SIG(C_SEND_DROP_PARTY, PartyControl) \
+ DEF_PRIV_SIG(C_DROP_PARTY_ACK_indication, PartyControl) \
+ DEF_PRIV_SIG(C_SEND_DROP_PARTY_ACK, PartyControl) \
+ DEF_PRIV_SIG(C_ADD_PARTY_REJ_indication, PartyControl) \
+ DEF_PRIV_SIG(C_SEND_ADD_PARTY_REJ, PartyControl) \
+ DEF_PRIV_SIG(C_SEND_STATUS_ENQ, PartyControl) \
+ DEF_PRIV_SIG(C_PARTY_DESTROYED, PartyControl) \
+ DEF_PRIV_SIG(C_END, CallControl)
+
+#define DEF_PARTY_SIGS \
+ DEF_PRIV_SIG(P_SETUP, CallControl) \
+ DEF_PRIV_SIG(P_ALERTING, CallControl) \
+ DEF_PRIV_SIG(P_CONNECT, CallControl) \
+ DEF_PRIV_SIG(P_CONNECT_ACK, CallControl) \
+ DEF_PRIV_SIG(P_RELEASE, CallControl) \
+ DEF_PRIV_SIG(P_RELEASE_COMPL, CallControl) \
+ DEF_PRIV_SIG(P_STATUS, CallControl) \
+ DEF_PRIV_SIG(P_ADD_PARTY, CallControl) \
+ DEF_PRIV_SIG(P_PARTY_ALERTING, CallControl) \
+ DEF_PRIV_SIG(P_ADD_PARTY_ACK, CallControl) \
+ DEF_PRIV_SIG(P_ADD_PARTY_REJ, CallControl) \
+ DEF_PRIV_SIG(P_DROP_PARTY, CallControl) \
+ DEF_PRIV_SIG(P_DROP_PARTY_ACK, CallControl) \
+ DEF_PRIV_SIG(P_SETUP_request, CallControl) \
+ DEF_PRIV_SIG(P_SETUP_response, CallControl) \
+ DEF_PRIV_SIG(P_SETUP_COMPL_request, CallControl) \
+ DEF_PRIV_SIG(P_ALERTING_request, CallControl) \
+ DEF_PRIV_SIG(P_RELEASE_request, CallControl) \
+ DEF_PRIV_SIG(P_RELEASE_response, CallControl) \
+ DEF_PRIV_SIG(P_RELEASE_confirm, CallControl) \
+ DEF_PRIV_SIG(P_STATUS_ENQUIRY_request, CallControl) \
+ DEF_PRIV_SIG(P_ADD_PARTY_request, CallControl) \
+ DEF_PRIV_SIG(P_PARTY_ALERTING_request, CallControl) \
+ DEF_PRIV_SIG(P_ADD_PARTY_ACK_request, CallControl) \
+ DEF_PRIV_SIG(P_ADD_PARTY_REJ_request, CallControl) \
+ DEF_PRIV_SIG(P_DROP_PARTY_request, CallControl) \
+ DEF_PRIV_SIG(P_DROP_PARTY_ACK_request, CallControl) \
+ DEF_PRIV_SIG(P_PARTY_DELETE, PartyControl) \
+ DEF_PRIV_SIG(P_T397, PartyControl) \
+ DEF_PRIV_SIG(P_T398, PartyControl) \
+ DEF_PRIV_SIG(P_T399, PartyControl) \
+ DEF_PRIV_SIG(P_END, PartyControl)
+
+
+#define DEF_PRIV_SIG(NAME, FROM) SIG##NAME,
+enum coord_sig {
+ DEF_COORD_SIGS
+};
+enum respond_sig {
+ DEF_RESPOND_SIGS
+};
+enum start_sig {
+ DEF_START_SIGS
+};
+enum call_sig {
+ DEF_CALL_SIGS
+};
+enum party_sig {
+ DEF_PARTY_SIGS
+};
+#undef DEF_PRIV_SIG
+
+/*************************************************************
+ *
+ * SIGNALS and SIGNAL QUEUES
+ */
+enum {
+ SIG_COORD,
+ SIG_RESET_START,
+ SIG_RESET_RESP,
+ SIG_CALL,
+ SIG_PARTY,
+};
+
+struct sig {
+ TAILQ_ENTRY(sig) link;
+ u_int type; /* one of the above */
+ struct call *call; /* call to send to */
+ struct party *party; /* party to send to */
+ u_int32_t sig; /* the signal */
+ u_int32_t cookie; /* user cookie */
+ struct uni_msg *msg; /* attached message */
+ struct uni_all *u; /* dito */
+};
+TAILQ_HEAD(sigqueue, sig);
+
+#define SIGQ_CLEAR(Q) \
+ do { \
+ struct sig *s; \
+ while(!TAILQ_EMPTY(Q)) { \
+ s = TAILQ_FIRST(Q); \
+ TAILQ_REMOVE(Q, s, link); \
+ if(s->msg) uni_msg_destroy(s->msg); \
+ if(s->u) UNI_FREE(s->u); \
+ SIG_FREE(s); \
+ } \
+ } while(0)
+
+void uni_sig_party(struct party *, enum party_sig, u_int32_t cookie,
+ struct uni_msg *, struct uni_all *);
+void uni_sig_call(struct call *, enum call_sig, u_int32_t cookie,
+ struct uni_msg *, struct uni_all *);
+void uni_sig_coord(struct uni *, enum coord_sig, u_int32_t cookie,
+ struct uni_msg *);
+void uni_sig_start(struct uni *, enum start_sig, u_int32_t cookie,
+ struct uni_msg *, struct uni_all *);
+void uni_sig_respond(struct uni *, enum respond_sig, u_int32_t cookie,
+ struct uni_msg *, struct uni_all *);
+
+/*************************************************************
+ *
+ * CALL INSTANCES
+ */
+struct party {
+ struct call *call;
+ TAILQ_ENTRY(party) link;
+ u_int epref; /* endpoint reference */
+ u_int flags; /* flags */
+ enum uni_epstate state; /* party state */
+
+ struct uni_timer t397; /* T397 */
+ struct uni_timer t398; /* T398 */
+ struct uni_timer t399; /* T399 */
+};
+#define PARTY_MINE 0x0001 /* must be 1 */
+#define PARTY_CONNECT 0x0002 /* connect request from this party */
+
+TAILQ_HEAD(partyqueue, party);
+
+void uni_destroy_party(struct party *, int);
+struct party *uni_find_party(struct call *, struct uni_ie_epref *);
+struct party *uni_find_partyx(struct call *, u_int epref, u_int mine);
+struct party *uni_create_party(struct call *, struct uni_ie_epref *);
+struct party *uni_create_partyx(struct call *, u_int epref, u_int mine, u_int32_t cookie);
+u_int uni_party_act_count(struct call *, int);
+
+enum call_type {
+ CALL_NULL, /* not known yet */
+ CALL_P2P, /* normal point-to-point call */
+ CALL_COBI, /* Q.2932.1 COBI call */
+ CALL_ROOT, /* point-to-multipoint root */
+ CALL_LEAF, /* point-to-multipoint leaf */
+};
+
+enum call_state {
+ CALLST_NULL,
+ CALLST_U1, CALLST_U3, CALLST_U4, CALLST_U6, CALLST_U7, CALLST_U8,
+ CALLST_U9, CALLST_U10, CALLST_U11, CALLST_U12,
+ CALLST_N1, CALLST_N3, CALLST_N4, CALLST_N6, CALLST_N7, CALLST_N8,
+ CALLST_N9, CALLST_N10, CALLST_N11, CALLST_N12
+};
+
+struct call {
+ TAILQ_ENTRY(call) link; /* link between calls */
+ struct uni *uni; /* backpointer to owning UNI */
+ u_int cref; /* call reference value or lij seqno */
+ u_int mine; /* if TRUE this is my call */
+ enum call_type type; /* what call is it */
+ enum call_state cstate; /* the state of the call */
+ struct uni_ie_connid connid; /* the connection ID */
+ struct uni_setup msg_setup; /* retransmission */
+ struct uni_release msg_release; /* retransmission */
+ struct uni_ie_epref stat_epref; /* retransmission */
+ struct partyqueue parties;
+ u_int se_active; /* status enquiry active */
+ u_int epref_alloc;
+
+ struct uni_timer t308; /* T303 */
+ u_int cnt308;
+
+ struct uni_timer t303; /* T303 */
+ u_int cnt303;
+
+ struct uni_timer t301; /* T301 */
+ struct uni_timer t310; /* T310 */
+ struct uni_timer t313; /* T313 */
+
+ struct uni_timer t322; /* T322 */
+ u_int cnt322;
+};
+
+TAILQ_HEAD(callqueue, call);
+
+struct call *uni_find_call(struct uni *, struct uni_cref *);
+struct call *uni_find_callx(struct uni *, u_int cref, u_int mine);
+struct call *uni_create_call(struct uni *, u_int cref, u_int mine,
+ u_int32_t cookie);
+struct call *uni_create_new_call(struct uni *, u_int32_t cookie);
+void uni_destroy_call(struct call *, int);
+
+void uni_bad_message(struct call *, struct uni_all *, u_int,
+ struct uni_ie_epref *, int);
+
+extern const struct callstates {
+ const char *name;
+ enum uni_callstate ext;
+} callstates[];
+
+/*************************************************************
+ *
+ * UNI INSTANCE
+ */
+struct uni {
+ void *arg; /* user arg */
+ const struct uni_funcs *funcs;
+
+ enum uni_proto proto; /* protocol */
+ struct unicx cx; /* decoding/coding context */
+ int sb_tb : 1; /* Sb-Tb/Tb point */
+
+ struct sigqueue workq; /* work queue */
+ struct sigqueue delq; /* delayed signal queue */
+ int working;
+
+ u_int32_t cref_alloc;
+
+ enum cu_stat custat; /* coordinator state */
+ struct uni_timer t309;
+ u_int timer309;
+
+ enum uni_callstate glob_start;
+ enum uni_callstate glob_respond;
+ struct uni_timer t316;
+ struct uni_timer t317;
+ struct uni_ie_connid connid_start;
+ struct uni_ie_connid connid_respond;
+ u_int cnt316;
+ struct uni_ie_restart restart_start;
+
+ struct callqueue calls;
+
+ struct uni_ie_cause cause; /* working area for verify */
+
+ /* tuneable parameters */
+ u_int timer301;
+ u_int init303;
+ u_int timer303;
+ u_int init308;
+ u_int timer308;
+ u_int timer310;
+ u_int timer313;
+ u_int init316;
+ u_int timer316;
+ u_int timer317;
+ u_int timer322;
+ u_int init322;
+ u_int timer397;
+ u_int timer398;
+ u_int timer399;
+
+ u_int debug[UNI_MAXFACILITY];
+};
+
+void uniapi_uni_error(struct uni *uni, u_int32_t reason, u_int32_t cookie,
+ u_int32_t state);
+void uniapi_call_error(struct call *c, u_int32_t reason, u_int32_t cookie);
+void uniapi_party_error(struct party *p, u_int32_t reason, u_int32_t cookie);
+
+/*************************************************************
+ *
+ * INLINE FUNCTIONS
+ */
+
+/* Enqueue a signal in the working queue */
+void uni_enq_sig(struct uni *, u_int, struct call *, struct party *,
+ uint32_t, uint32_t, struct uni_msg *, struct uni_all *);
+
+/* Enqueue a signal in the delayed queue */
+void uni_delenq_sig(struct uni *, u_int, struct call *, struct party *,
+ uint32_t, uint32_t, struct uni_msg *, struct uni_all *);
+
+/* Enqueue a signal to the coordinator */
+#define uni_enq_coord(UNI, SIG, COOKIE, MSG) do { \
+ uni_enq_sig((UNI), SIG_COORD, NULL, NULL, \
+ (SIG), (COOKIE), (MSG), NULL); \
+ } while (0)
+
+/* Enqueue a delayed signal to the coordinator */
+#define uni_delenq_coord(UNI, SIG, COOKIE, MSG) do { \
+ uni_delenq_sig((UNI), SIG_COORD, NULL, NULL, \
+ (SIG), (COOKIE), (MSG), NULL); \
+ } while (0)
+
+/* Enqueue a signal to a call */
+#define uni_enq_call(CALL, SIG, COOKIE, MSG, U) do { \
+ uni_enq_sig((CALL)->uni, SIG_CALL, (CALL), NULL, \
+ (SIG), (COOKIE), (MSG), (U)); \
+ } while (0)
+
+/* Enqueue a signal to a party */
+#define uni_enq_party(PARTY, SIG, COOKIE, MSG, U) do { \
+ uni_enq_sig((PARTY)->call->uni, SIG_PARTY, (PARTY)->call, \
+ (PARTY), (SIG), (COOKIE), (MSG), (U)); \
+ } while (0)
+
+/* Enqueue a signal to RESET-START */
+#define uni_enq_start(UNI, SIG, COOKIE, MSG, U) do { \
+ uni_enq_sig((UNI), SIG_RESET_START, NULL, NULL, \
+ (SIG), (COOKIE), (MSG), (U)); \
+ } while (0)
+
+/* Enqueue a signal to RESET-RESPOND */
+#define uni_enq_resp(UNI, SIG, COOKIE, MSG, U) do { \
+ uni_enq_sig((UNI), SIG_RESET_RESP, NULL, NULL, \
+ (SIG), (COOKIE), (MSG), (U)); \
+ } while (0)
+
+int uni_send_output(struct uni_all *u, struct uni *uni);
+void uni_undel(struct uni *, int (*)(struct sig *, void *), void *);
+void uni_delsig(struct uni *, u_int, struct call *, struct party *);
+
+void uni_release_compl(struct call *, struct uni_all *);
+
+/*************************************************************/
+/*
+ * Message verification.
+ */
+#define MANDATE_IE(UNI,MSG,IE) \
+ do { \
+ if (!IE_ISGOOD(MSG)) \
+ uni_mandate_ie(UNI, IE); \
+ } while(0)
+
+enum verify {
+ VFY_OK, /* ok */
+ VFY_RAP, /* report and proceed */
+ VFY_RAPU, /* report and proceed becuase of unknown IEs */
+ VFY_I, /* ignore */
+ VFY_CLR, /* clear call */
+ VFY_RAI, /* report and ignore */
+ VFY_RAIM, /* report and ignore because if mandat. IE miss */
+};
+
+void uni_mandate_ie(struct uni *, enum uni_ietype);
+void uni_mandate_epref(struct uni *, struct uni_ie_epref *);
+enum verify uni_verify(struct uni *, enum uni_msgact);
+void uni_respond_status_verify(struct uni *, struct uni_cref *,
+ enum uni_callstate, struct uni_ie_epref *, enum uni_epstate);
+void uni_vfy_remove_unknown(struct uni *);
+void uni_vfy_remove_cause(struct uni *);
+void uni_vfy_collect_ies(struct uni *);
+
+
+void uni_respond_status(struct uni *uni, struct uni_cref *cref,
+ enum uni_callstate cs, enum uni_cause c1);
+void uni_respond_status_mtype(struct uni *uni, struct uni_cref *cref,
+ enum uni_callstate cs, enum uni_cause c1, u_int mtype);
+
+#define FOREACH_ERR(E, UNI) \
+ for ((E) = (UNI)->cx.err; (E) < (UNI)->cx.err + (UNI)->cx.errcnt; (E)++)
+
+#define ALLOC_API(TYPE,API) \
+ ({ \
+ TYPE *_tmp = NULL; \
+ \
+ if(((API) = uni_msg_alloc(sizeof(TYPE))) != NULL) { \
+ _tmp = uni_msg_wptr((API), TYPE *); \
+ (API)->b_wptr += sizeof(TYPE); \
+ memset(_tmp, 0, sizeof(TYPE)); \
+ } \
+ _tmp; \
+ })
+
+#define VERBOSE(UNI, FAC, LEVEL, FMT, ARGS...) do { \
+ if ((UNI)->debug[(FAC)] >= (LEVEL)) { \
+ (UNI)->funcs->verbose((UNI), (UNI)->arg, (FAC), \
+ FMT , ## ARGS); \
+ } \
+ } while(0)
+
+#define VERBOSE0(UNI, FAC, FMT, ARGS...) do { \
+ (UNI)->funcs->verbose((UNI), (UNI)->arg, (FAC), FMT , \
+ ## ARGS); \
+ } while(0)
+
+#define TIMER_INIT_UNI(U,T) _TIMER_INIT(U,T)
+#define TIMER_INIT_CALL(C,T) _TIMER_INIT(C,T)
+#define TIMER_INIT_PARTY(P,T) _TIMER_INIT(P,T)
+
+#define TIMER_DESTROY_UNI(U,T) _TIMER_DESTROY(U, (U)->T)
+#define TIMER_DESTROY_CALL(C,T) _TIMER_DESTROY((C)->uni, (C)->T)
+#define TIMER_DESTROY_PARTY(P,T) _TIMER_DESTROY((P)->call->uni, (P)->T)
+
+#define TIMER_STOP_UNI(U,T) _TIMER_STOP(U, (U)->T)
+#define TIMER_STOP_CALL(C,T) _TIMER_STOP((C)->uni, (C)->T)
+#define TIMER_STOP_PARTY(P,T) _TIMER_STOP((P)->call->uni, (P)->T)
+
+#define TIMER_START_UNI(U,T,N) _TIMER_START(U, U, (U)->T, N, _##T##_func)
+#define TIMER_START_CALL(C,T,N) _TIMER_START(C->uni, C, (C)->T, N, _##T##_func)
+#define TIMER_START_PARTY(P,T,N) _TIMER_START(P->call->uni, P, (P)->T, N, _##T##_func)
+
+#endif
diff --git a/sys/contrib/ngatm/netnatm/sig/unisig.h b/sys/contrib/ngatm/netnatm/sig/unisig.h
new file mode 100644
index 0000000..2f845f9
--- /dev/null
+++ b/sys/contrib/ngatm/netnatm/sig/unisig.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2001-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/sig/unisig.h,v 1.3 2003/09/19 12:03:34 hbb Exp $
+ *
+ * Utility functions for signalling stuff
+ */
+#ifndef _NETNATM_SIG_UNISIG_H_
+#define _NETNATM_SIG_UNISIG_H_
+
+#include <netnatm/sig/unidef.h>
+
+/* names */
+const char *uni_signame(enum uni_sig);
+const char *uni_facname(enum uni_verb);
+
+/* return a string for the error code */
+const char *uni_strerr(u_int _err);
+
+/* format an API message */
+void uni_print_api(char *_buf, size_t _bufsiz, u_int _type, u_int _cookie,
+ const void *_msg, struct unicx *_cx);
+
+#endif
OpenPOWER on IntegriCloud