diff options
author | harti <harti@FreeBSD.org> | 2003-11-07 08:46:22 +0000 |
---|---|---|
committer | harti <harti@FreeBSD.org> | 2003-11-07 08:46:22 +0000 |
commit | a92d6f1ef6b5ff4215d1d644cbf12ab1fcb8f8c0 (patch) | |
tree | e4cb95f047c8ee14d254892524f10bddcd806c07 /sys/contrib/ngatm | |
parent | d2e4a0c64439be23c448c5da91bb2bbfa709d38c (diff) | |
download | FreeBSD-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.awk | 80 | ||||
-rw-r--r-- | sys/contrib/ngatm/netnatm/sig/genmsgcpyh.awk | 55 | ||||
-rw-r--r-- | sys/contrib/ngatm/netnatm/sig/sig_call.c | 4300 | ||||
-rw-r--r-- | sys/contrib/ngatm/netnatm/sig/sig_coord.c | 1171 | ||||
-rw-r--r-- | sys/contrib/ngatm/netnatm/sig/sig_party.c | 1353 | ||||
-rw-r--r-- | sys/contrib/ngatm/netnatm/sig/sig_print.c | 622 | ||||
-rw-r--r-- | sys/contrib/ngatm/netnatm/sig/sig_reset.c | 824 | ||||
-rw-r--r-- | sys/contrib/ngatm/netnatm/sig/sig_uni.c | 749 | ||||
-rw-r--r-- | sys/contrib/ngatm/netnatm/sig/sig_verify.c | 442 | ||||
-rw-r--r-- | sys/contrib/ngatm/netnatm/sig/uni.h | 106 | ||||
-rw-r--r-- | sys/contrib/ngatm/netnatm/sig/unidef.h | 474 | ||||
-rw-r--r-- | sys/contrib/ngatm/netnatm/sig/unimkmsg.h | 159 | ||||
-rw-r--r-- | sys/contrib/ngatm/netnatm/sig/unipriv.h | 544 | ||||
-rw-r--r-- | sys/contrib/ngatm/netnatm/sig/unisig.h | 49 |
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 |