1122205Sharti/*
2122205Sharti * Copyright (c) 1996-2003
3122205Sharti *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4122205Sharti * 	All rights reserved.
5122205Sharti *
6122205Sharti * Redistribution and use in source and binary forms, with or without
7122205Sharti * modification, are permitted provided that the following conditions
8122205Sharti * are met:
9122205Sharti * 1. Redistributions of source code must retain the above copyright
10122205Sharti *    notice, this list of conditions and the following disclaimer.
11122205Sharti * 2. Redistributions in binary form must reproduce the above copyright
12122205Sharti *    notice, this list of conditions and the following disclaimer in the
13122205Sharti *    documentation and/or other materials provided with the distribution.
14122205Sharti *
15122205Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16122205Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17122205Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18122205Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19122205Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20122205Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21122205Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22122205Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23122205Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24122205Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25122205Sharti * SUCH DAMAGE.
26122205Sharti *
27122205Sharti * Author: Hartmut Brandt <harti@freebsd.org>
28122205Sharti *
29133492Sharti * $Begemot: libunimsg/netnatm/sig/sig_call.c,v 1.65 2004/08/05 07:11:00 brandt Exp $
30122205Sharti *
31122205Sharti * Call instance handling
32122205Sharti *
33122205Sharti * Note:
34122205Sharti *	In all functions that handle messages from the user or from
35122205Sharti *	the SAAL, commit memory allocation always at the begin of the
36122205Sharti *	function. If allocation fails, ignore saal messages and
37122205Sharti *	respond with an error to user messages.
38122205Sharti */
39122205Sharti
40122205Sharti#include <netnatm/unimsg.h>
41122205Sharti#include <netnatm/saal/sscfudef.h>
42122205Sharti#include <netnatm/msg/unistruct.h>
43122205Sharti#include <netnatm/msg/unimsglib.h>
44122205Sharti#include <netnatm/sig/uni.h>
45122205Sharti
46122205Sharti#include <netnatm/sig/unipriv.h>
47122205Sharti#include <netnatm/sig/unimkmsg.h>
48122205Sharti#include <netnatm/sig/unimsgcpy.h>
49122205Sharti
50122205Shartistatic enum call_state state_compat(struct call *, enum uni_callstate);
51122205Shartistatic void respond_drop_party_ack(struct call *, struct uni_ie_epref *, u_int);
52122205Sharti
53122205Sharti
54133492Sharti#define DEF_PRIV_SIG(NAME, FROM)	[SIG##NAME] =	"SIG"#NAME,
55122205Shartistatic const char *const call_sigs[] = {
56122205Sharti	DEF_CALL_SIGS
57122205Sharti};
58122205Sharti#undef DEF_PRIV_SIG
59122205Sharti
60122205ShartiTIMER_FUNC_CALL(t308, t308_func)
61122205ShartiTIMER_FUNC_CALL(t303, t303_func)
62122205ShartiTIMER_FUNC_CALL(t301, t301_func)
63122205ShartiTIMER_FUNC_CALL(t310, t310_func)
64122205ShartiTIMER_FUNC_CALL(t313, t313_func)
65122205ShartiTIMER_FUNC_CALL(t322, t322_func)
66122205Sharti
67122205Sharticonst struct callstates callstates[] = {
68133492Sharti	[CALLST_NULL] =	{ "NU0",	UNI_CALLSTATE_U0 },
69133492Sharti	[CALLST_U1] =	{ "U1",		UNI_CALLSTATE_U1 },
70133492Sharti	[CALLST_U3] =	{ "U3",		UNI_CALLSTATE_U3 },
71133492Sharti	[CALLST_U4] =	{ "U4",		UNI_CALLSTATE_U4 },
72133492Sharti	[CALLST_U6] =	{ "U6",		UNI_CALLSTATE_U6 },
73133492Sharti	[CALLST_U7] =	{ "U7",		UNI_CALLSTATE_U7 },
74133492Sharti	[CALLST_U8] =	{ "U8",		UNI_CALLSTATE_U8 },
75133492Sharti	[CALLST_U9] =	{ "U9",		UNI_CALLSTATE_U9 },
76133492Sharti	[CALLST_U10] =	{ "U10",	UNI_CALLSTATE_U10 },
77133492Sharti	[CALLST_U11] =	{ "U11",	UNI_CALLSTATE_U11 },
78133492Sharti	[CALLST_U12] =	{ "U12",	UNI_CALLSTATE_U12 },
79133492Sharti	[CALLST_N1] =	{ "N1",		UNI_CALLSTATE_N1 },
80133492Sharti	[CALLST_N3] =	{ "N3",		UNI_CALLSTATE_N3 },
81133492Sharti	[CALLST_N4] =	{ "N4",		UNI_CALLSTATE_N4 },
82133492Sharti	[CALLST_N6] =	{ "N6",		UNI_CALLSTATE_N6 },
83133492Sharti	[CALLST_N7] =	{ "N7",		UNI_CALLSTATE_N7 },
84133492Sharti	[CALLST_N8] =	{ "N8",		UNI_CALLSTATE_N8 },
85133492Sharti	[CALLST_N9] =	{ "N9",		UNI_CALLSTATE_N9 },
86133492Sharti	[CALLST_N10] =	{ "N10",	UNI_CALLSTATE_N10 },
87133492Sharti	[CALLST_N11] =	{ "N11",	UNI_CALLSTATE_N11 },
88133492Sharti	[CALLST_N12] =	{ "N12",	UNI_CALLSTATE_N12 },
89122205Sharti};
90122205Sharti
91122205Shartistatic void unx_send_add_party_rej(struct call *c, struct uni_all *u);
92122205Sharti
93122205Shartistatic __inline void
94122205Shartiset_call_state(struct call *c, enum call_state state)
95122205Sharti{
96122205Sharti	ASSERT(state == CALLST_NULL ||
97122205Sharti	    (c->uni->proto == UNIPROTO_UNI40U &&
98122205Sharti	     (state >= CALLST_U1 && state <= CALLST_U12)) ||
99122205Sharti	    (c->uni->proto == UNIPROTO_UNI40N &&
100122205Sharti	     (state >= CALLST_N1 && state <= CALLST_N12)),
101122205Sharti	    ("setting wrong callstate for proto %u: %u", c->uni->proto, state));
102122205Sharti
103122205Sharti	if (c->cstate != state) {
104122205Sharti		VERBOSE(c->uni, UNI_FAC_CALL, 1, "call %d/%d %s -> %s",
105122205Sharti		    c->cref, c->mine, callstates[c->cstate].name,
106122205Sharti		    callstates[state].name);
107122205Sharti		c->cstate = state;
108122205Sharti	}
109122205Sharti}
110122205Sharti
111122205Shartistatic enum uni_callstate
112122205Shartimap_callstate(enum call_state state)
113122205Sharti{
114122205Sharti	return (callstates[state].ext);
115122205Sharti}
116122205Sharti
117122205Sharti/*
118122205Sharti * Find the call. Assume, that the cref is one of a message just received.
119122205Sharti * That is, if the call reference flag is 0 it is his call, if it is 1 it
120122205Sharti * is my call.
121122205Sharti */
122122205Shartistruct call *
123122205Shartiuni_find_call(struct uni *uni, struct uni_cref *cref)
124122205Sharti{
125122205Sharti	struct call *c;
126122205Sharti
127122205Sharti	TAILQ_FOREACH(c, &uni->calls, link)
128122205Sharti		if (c->cref == cref->cref && (!c->mine == !cref->flag))
129122205Sharti			return (c);
130122205Sharti	return (NULL);
131122205Sharti}
132122205Shartistruct call *
133122205Shartiuni_find_callx(struct uni *uni, u_int cref, u_int mine)
134122205Sharti{
135122205Sharti	struct call *c;
136122205Sharti
137122205Sharti	TAILQ_FOREACH(c, &uni->calls, link)
138122205Sharti		if (c->cref == cref && !c->mine == !mine)
139122205Sharti			return (c);
140122205Sharti	return (NULL);
141122205Sharti}
142122205Sharti
143122205Sharti/*
144122205Sharti * Create a new call instance. The type must be set by the caller.
145122205Sharti */
146122205Shartistruct call *
147131826Shartiuni_create_call(struct uni *uni, u_int cref, u_int mine, uint32_t cookie)
148122205Sharti{
149122205Sharti	struct call *c;
150122205Sharti	struct uniapi_call_created *ind;
151122205Sharti	struct uni_msg *api;
152122205Sharti
153122205Sharti	if ((c = CALL_ALLOC()) == NULL)
154122205Sharti		return (NULL);
155122205Sharti
156122205Sharti	if ((ind = ALLOC_API(struct uniapi_call_created, api)) == NULL) {
157122205Sharti		CALL_FREE(c);
158122205Sharti		return (NULL);
159122205Sharti	}
160122205Sharti	ind->cref.cref = cref;
161122205Sharti	ind->cref.flag = mine;
162122205Sharti
163122205Sharti	c->uni = uni;
164122205Sharti	c->type = CALL_NULL;
165122205Sharti	c->cref = cref;
166122205Sharti	c->mine = mine;
167122205Sharti	c->cstate = CALLST_NULL;
168122205Sharti	TAILQ_INIT(&c->parties);
169122205Sharti
170122205Sharti	TIMER_INIT_CALL(c, t301);
171122205Sharti	TIMER_INIT_CALL(c, t303);
172122205Sharti	TIMER_INIT_CALL(c, t308);
173122205Sharti	TIMER_INIT_CALL(c, t310);
174122205Sharti	TIMER_INIT_CALL(c, t313);
175122205Sharti	TIMER_INIT_CALL(c, t322);
176122205Sharti
177122205Sharti	TAILQ_INSERT_HEAD(&uni->calls, c, link);
178122205Sharti
179122205Sharti	uni->funcs->uni_output(uni, uni->arg, UNIAPI_CALL_CREATED, cookie, api);
180122205Sharti
181122205Sharti	VERBOSE(c->uni, UNI_FAC_CALL, 1, "created call %u/%s",
182122205Sharti	    c->cref, c->mine ? "mine" : "his");
183122205Sharti
184122205Sharti	return (c);
185122205Sharti}
186122205Sharti
187122205Shartistruct call *
188131826Shartiuni_create_new_call(struct uni *uni, uint32_t cookie)
189122205Sharti{
190122205Sharti	struct call *c;
191131826Sharti	uint32_t old = uni->cref_alloc++;
192122205Sharti
193122205Sharti  again:
194122205Sharti	if (uni->cref_alloc == (1 << 23))
195122205Sharti		uni->cref_alloc = 1;
196122205Sharti	if (uni->cref_alloc == old)
197122205Sharti		return (NULL);	/* all crefs exhausted!!! */
198122205Sharti	TAILQ_FOREACH(c, &uni->calls, link)
199122205Sharti		if (c->mine && c->cref == uni->cref_alloc) {
200122205Sharti			uni->cref_alloc++;
201122205Sharti			goto again;
202122205Sharti		}
203122205Sharti	return (uni_create_call(uni, uni->cref_alloc, 1, cookie));
204122205Sharti}
205122205Sharti
206122205Sharti/*
207122205Sharti * Assume timers are all stopped. Memory is not actually freed unless
208122205Sharti * the reference count drops to 0.
209122205Sharti * This function is assumed to remove the call from the parent UNI's
210122205Sharti * call queue.
211122205Sharti */
212122205Shartivoid
213122205Shartiuni_destroy_call(struct call *c, int really)
214122205Sharti{
215122205Sharti	struct uniapi_call_destroyed *ind;
216122205Sharti	struct uni_msg *api;
217122205Sharti	struct party *p;
218122205Sharti
219122205Sharti	VERBOSE(c->uni, UNI_FAC_CALL, 1, "destroying call %u/%s",
220122205Sharti	    c->cref, c->mine ? "mine" : "his");
221122205Sharti
222122205Sharti	TIMER_DESTROY_CALL(c, t301);
223122205Sharti	TIMER_DESTROY_CALL(c, t303);
224122205Sharti	TIMER_DESTROY_CALL(c, t308);
225122205Sharti	TIMER_DESTROY_CALL(c, t310);
226122205Sharti	TIMER_DESTROY_CALL(c, t313);
227122205Sharti	TIMER_DESTROY_CALL(c, t322);
228122205Sharti	TAILQ_REMOVE(&c->uni->calls, c, link);
229122205Sharti
230122205Sharti	uni_delsig(c->uni, SIG_CALL, c, NULL);
231122205Sharti
232122205Sharti	while ((p = TAILQ_FIRST(&c->parties)) != NULL) {
233122205Sharti		TAILQ_REMOVE(&c->parties, p, link);
234122205Sharti		uni_destroy_party(p, really);
235122205Sharti	}
236122205Sharti
237122205Sharti	if (!really) {
238122205Sharti		ind = ALLOC_API(struct uniapi_call_destroyed, api);
239122205Sharti		if (ind != NULL) {
240122205Sharti			ind->cref.cref = c->cref;
241122205Sharti			ind->cref.flag = c->mine;
242122205Sharti
243122205Sharti			uni_enq_coord(c->uni, SIGO_CALL_DESTROYED, 0, api);
244122205Sharti		}
245122205Sharti
246122205Sharti		uni_enq_call(c, SIGC_CALL_DELETE, 0, NULL, NULL);
247122205Sharti		return;
248122205Sharti	}
249122205Sharti
250122205Sharti	CALL_FREE(c);
251122205Sharti}
252122205Sharti
253122205Shartistatic void
254122205Shartiallocate_epref(struct call *c, struct uni_ie_epref *epref)
255122205Sharti{
256122205Sharti	struct party *p;
257131826Sharti	uint32_t old = c->epref_alloc++;
258122205Sharti
259122205Sharti  again:
260122205Sharti	if (c->epref_alloc == (1 << 15))
261122205Sharti		c->epref_alloc = 0;
262122205Sharti	if (c->epref_alloc == old)
263122205Sharti		return;		/* all crefs exhausted!!! */
264122205Sharti	TAILQ_FOREACH(p, &c->parties, link)
265122205Sharti		if (p->epref == c->epref_alloc) {
266122205Sharti			c->epref_alloc++;
267122205Sharti			goto again;
268122205Sharti		}
269122205Sharti	IE_SETPRESENT(*epref);
270122205Sharti	epref->flag = 0;
271122205Sharti	epref->epref = c->epref_alloc;
272122205Sharti
273122205Sharti	epref->h.coding = UNI_CODING_ITU;
274122205Sharti	epref->h.act = UNI_IEACT_DEFAULT;
275122205Sharti}
276122205Sharti
277122205Shartistatic void
278122205Shartireset_all_timers(struct call *c)
279122205Sharti{
280122205Sharti	TIMER_STOP_CALL(c, t301);
281122205Sharti	TIMER_STOP_CALL(c, t303);
282122205Sharti	TIMER_STOP_CALL(c, t308);
283122205Sharti	TIMER_STOP_CALL(c, t310);
284122205Sharti	TIMER_STOP_CALL(c, t313);
285122205Sharti	TIMER_STOP_CALL(c, t322);
286122205Sharti}
287122205Sharti
288122205Sharti/*
289122205Sharti * Initiate call clearing because of a problem. This is label D in
290122205Sharti * the SDLs and is called from many places.
291122205Sharti * The call must have constructed the cause IE in struct call.
292122205Sharti *
293122205Sharti * Q.2971:Call-Control-U 27/39
294122205Sharti * Q.2971:Call-Control-N 28/39
295122205Sharti *
296122205Sharti * Memory problems are handled differently here: we simply ignore them
297122205Sharti * by not sending messages or user indications. Because of T308 we
298122205Sharti * may be lucky to send the message in a second run.
299122205Sharti *
300122205Sharti * It is assumed, that the cause for the release is constructed by
301122205Sharti * the calling function in uni->cause.
302122205Sharti */
303122205Shartistatic void
304122205Sharticlear_callD(struct call *c)
305122205Sharti{
306122205Sharti	struct uni_msg *api;
307122205Sharti	struct uniapi_release_indication *ind;
308122205Sharti	struct party *p;
309122205Sharti	struct uni_all *rel;
310122205Sharti
311122205Sharti	/*
312122205Sharti	 * Send indication to API
313122205Sharti	 */
314122205Sharti	if ((ind = ALLOC_API(struct uniapi_release_indication, api)) != NULL) {
315122205Sharti		ind->release.hdr.cref.cref = c->cref;
316122205Sharti		ind->release.hdr.cref.flag = c->mine;
317122205Sharti		ind->release.hdr.act = UNI_MSGACT_DEFAULT;
318122205Sharti		ind->release.cause[0] = c->uni->cause;
319122205Sharti
320122205Sharti		c->uni->funcs->uni_output(c->uni, c->uni->arg,
321122205Sharti		    UNIAPI_RELEASE_indication, 0, api);
322122205Sharti	}
323122205Sharti
324122205Sharti	reset_all_timers(c);
325122205Sharti
326122205Sharti	if (c->type == CALL_LEAF || c->type == CALL_ROOT) {
327122205Sharti		TAILQ_FOREACH(p, &c->parties, link) {
328122205Sharti			uni_enq_party(p, SIGP_RELEASE_request, 0, NULL, NULL);
329122205Sharti		}
330122205Sharti	}
331122205Sharti
332122205Sharti	memset(&c->msg_release, 0, sizeof(c->msg_release));
333122205Sharti	c->msg_release.cause[0] = c->uni->cause;
334122205Sharti
335122205Sharti	if ((rel = UNI_ALLOC()) != NULL) {
336122205Sharti		rel->u.release = c->msg_release;
337122205Sharti		MK_MSG_ORIG(rel, UNI_RELEASE, c->cref, !c->mine);
338122205Sharti		(void)uni_send_output(rel, c->uni);
339122205Sharti		UNI_FREE(rel);
340122205Sharti	}
341122205Sharti
342122205Sharti	TIMER_START_CALL(c, t308, c->uni->timer308);
343122205Sharti	c->cnt308 = 0;
344122205Sharti
345122205Sharti	if (c->uni->proto == UNIPROTO_UNI40N)
346122205Sharti		set_call_state(c, CALLST_N12);
347122205Sharti	else
348122205Sharti		set_call_state(c, CALLST_U11);
349122205Sharti}
350122205Sharti
351122205Sharti
352122205Sharti/**********************************************************************/
353122205Sharti/*
354122205Sharti * SETUP message in state NULL
355122205Sharti *
356122205Sharti * Q.2971:Call-Control-U 4/39
357122205Sharti * Q.2971:Call-Control-N 4/39
358122205Sharti */
359122205Shartistatic void
360122205Shartiun0_setup(struct call *c, struct uni_msg *m, struct uni_all *u,
361122205Sharti    enum call_state new_state)
362122205Sharti{
363122205Sharti	struct uni_all *resp;
364122205Sharti	struct party *p;
365122205Sharti	struct uniapi_setup_indication *ind;
366122205Sharti	struct uni_msg *api;
367122205Sharti	enum verify v;
368122205Sharti
369122205Sharti	if ((ind = ALLOC_API(struct uniapi_setup_indication, api)) == NULL) {
370122205Sharti  clear:
371122205Sharti		uni_destroy_call(c, 0);
372122205Sharti		uni_msg_destroy(m);
373122205Sharti		UNI_FREE(u);
374122205Sharti		return;
375122205Sharti	}
376122205Sharti
377122205Sharti	/*
378122205Sharti	 * Analyze message
379122205Sharti	 */
380122205Sharti	(void)uni_decode_body(m, u, &c->uni->cx);
381122205Sharti	MANDATE_IE(c->uni, u->u.setup.bearer, UNI_IE_BEARER);
382122205Sharti	MANDATE_IE(c->uni, u->u.setup.traffic, UNI_IE_TRAFFIC);
383122205Sharti	MANDATE_IE(c->uni, u->u.setup.called, UNI_IE_CALLED);
384122205Sharti
385122205Sharti	/*
386122205Sharti	 * UNI4.0: 9.1.1.2 Notes 2/3
387122205Sharti	 */
388122205Sharti	if (!IE_ISPRESENT(u->u.setup.qos))
389122205Sharti		MANDATE_IE(c->uni, u->u.setup.exqos, UNI_IE_EXQOS);
390122205Sharti	if (!IE_ISPRESENT(u->u.setup.exqos))
391122205Sharti		MANDATE_IE(c->uni, u->u.setup.qos, UNI_IE_QOS);
392122205Sharti
393122205Sharti	/*
394122205Sharti	 * Q.2971
395122205Sharti	 */
396122205Sharti	if (IE_ISGOOD(u->u.setup.bearer) &&
397122205Sharti	    u->u.setup.bearer.cfg == UNI_BEARER_MP) {
398122205Sharti		if (IE_ISGOOD(u->u.setup.epref) &&
399122205Sharti		   u->u.setup.epref.flag == 1) {
400122205Sharti			IE_SETERROR(u->u.setup.epref);
401213789Srpaulo			(void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF,
402122205Sharti			    u->u.setup.epref.h.act, UNI_IERR_BAD);
403122205Sharti		}
404122205Sharti		uni_mandate_epref(c->uni, &u->u.setup.epref);
405122205Sharti	}
406122205Sharti
407122205Sharti	v = uni_verify(c->uni, u->u.hdr.act);
408122205Sharti	switch (v) {
409122205Sharti
410122205Sharti	  case VFY_RAI:
411122205Sharti		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
412122205Sharti		    UNI_CALLSTATE_U0, NULL, 0);
413122205Sharti		/* FALLTHRU */
414122205Sharti	  case VFY_I:
415122205Sharti		uni_msg_destroy(api);
416122205Sharti		goto clear;
417122205Sharti
418122205Sharti	  case VFY_RAIM:
419122205Sharti	  case VFY_CLR:
420122205Sharti		if ((resp = UNI_ALLOC()) != NULL) {
421122205Sharti			MK_MSG_RESP(resp, UNI_RELEASE_COMPL, &u->u.hdr.cref);
422122205Sharti			uni_vfy_collect_ies(c->uni);
423122205Sharti			resp->u.release_compl.cause[0] = c->uni->cause;
424122205Sharti			uni_send_output(resp, c->uni);
425122205Sharti			UNI_FREE(resp);
426122205Sharti		}
427122205Sharti		uni_msg_destroy(api);
428122205Sharti		goto clear;
429122205Sharti
430122205Sharti	  case VFY_RAP:
431122205Sharti	  case VFY_RAPU:
432122205Sharti		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
433122205Sharti		    map_callstate(new_state), NULL, 0);
434122205Sharti		/* FALLTHRU */
435122205Sharti	  case VFY_OK:
436122205Sharti		break;
437122205Sharti	}
438122205Sharti
439122205Sharti	if (u->u.setup.bearer.cfg == UNI_BEARER_P2P) {
440122205Sharti		c->type = CALL_P2P;
441122205Sharti
442122205Sharti	} else {
443122205Sharti		c->type = CALL_LEAF;
444122205Sharti		if ((p = uni_create_party(c, &u->u.setup.epref)) == NULL) {
445122205Sharti			uni_msg_destroy(api);
446122205Sharti			goto clear;
447122205Sharti		}
448122205Sharti		uni_enq_party(p, SIGP_SETUP, 0, NULL, NULL);
449122205Sharti	}
450122205Sharti
451122205Sharti	ind->setup.hdr = u->u.hdr;
452122205Sharti	copy_msg_setup(&u->u.setup, &ind->setup);
453122205Sharti	c->uni->funcs->uni_output(c->uni, c->uni->arg,
454122205Sharti	    UNIAPI_SETUP_indication, 0, api);
455122205Sharti
456122205Sharti	uni_msg_destroy(m);
457122205Sharti	UNI_FREE(u);
458122205Sharti
459122205Sharti	set_call_state(c, new_state);
460122205Sharti}
461122205Sharti
462122205Sharti/*
463122205Sharti * Setup.request from user
464122205Sharti *
465122205Sharti * Q.2971:Call-Control-U 4/39 (U0)
466122205Sharti * Q.2971:Call-Control-N 4/39 (N0)
467122205Sharti */
468122205Shartistatic void
469131826Shartiun0_setup_request(struct call *c, struct uni_msg *m, uint32_t cookie,
470122205Sharti    enum call_state new_state)
471122205Sharti{
472122205Sharti	struct uniapi_setup_request *arg =
473122205Sharti	    uni_msg_rptr(m, struct uniapi_setup_request *);
474122205Sharti	struct uni_setup *setup = &arg->setup;
475122205Sharti	struct uni_all *out;
476122205Sharti	struct party *p;
477122205Sharti
478122205Sharti	if (!IE_ISGOOD(setup->bearer)) {
479122205Sharti		uni_msg_destroy(m);
480122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_MISSING_IE, cookie);
481122205Sharti		uni_destroy_call(c, 0);
482122205Sharti		return;
483122205Sharti	}
484122205Sharti	if ((out = UNI_ALLOC()) == NULL) {
485122205Sharti		uni_msg_destroy(m);
486122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
487122205Sharti		uni_destroy_call(c, 0);
488122205Sharti		return;
489122205Sharti	}
490122205Sharti
491122205Sharti	c->msg_setup = *setup;
492122205Sharti
493122205Sharti	if (IE_ISGOOD(setup->connid))
494122205Sharti		c->connid = setup->connid;
495122205Sharti
496122205Sharti	if (setup->bearer.cfg == UNI_BEARER_P2P) {
497122205Sharti		c->type = CALL_P2P;
498122205Sharti	} else {
499122205Sharti		c->type = CALL_ROOT;
500122205Sharti
501122205Sharti		/*
502122205Sharti		 * If the user didn't specify a endpoint reference,
503122205Sharti		 * use 0. Use IE_IGNORE accoring to Appendix II Q.2971
504122205Sharti		 */
505122205Sharti		if (!IE_ISPRESENT(c->msg_setup.epref)) {
506122205Sharti			MK_IE_EPREF(c->msg_setup.epref, 0, 0);
507122205Sharti			if (c->uni->proto == UNIPROTO_UNI40N)
508122205Sharti				c->msg_setup.epref.h.act = UNI_IEACT_IGNORE;
509122205Sharti
510122205Sharti		} else if (!IE_ISGOOD(c->msg_setup.epref)) {
511122205Sharti			uni_msg_destroy(m);
512122205Sharti			uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
513122205Sharti			uni_destroy_call(c, 0);
514122205Sharti			return;
515122205Sharti		}
516122205Sharti		if ((p = uni_create_partyx(c, 0, 1, cookie)) == NULL) {
517122205Sharti			uni_msg_destroy(m);
518122205Sharti			uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
519122205Sharti			uni_destroy_call(c, 0);
520122205Sharti			return;
521122205Sharti		}
522122205Sharti		uni_enq_party(p, SIGP_SETUP_request, cookie, NULL, NULL);
523122205Sharti	}
524122205Sharti
525122205Sharti	uni_msg_destroy(m);
526122205Sharti
527122205Sharti	out->u.setup = c->msg_setup;
528122205Sharti	MK_MSG_ORIG(out, UNI_SETUP, c->cref, !c->mine);
529122205Sharti	(void)uni_send_output(out, c->uni);
530122205Sharti	UNI_FREE(out);
531122205Sharti
532122205Sharti	TIMER_START_CALL(c, t303, c->uni->timer303);
533122205Sharti	c->cnt303 = 0;
534122205Sharti
535122205Sharti	set_call_state(c, new_state);
536122205Sharti
537122205Sharti	uniapi_call_error(c, UNIAPI_OK, cookie);
538122205Sharti}
539122205Sharti
540122205Sharti/*
541122205Sharti * CALL PROCEEDING message
542122205Sharti *
543122205Sharti * Q.2971:Call-Control-U 6/39 (in U1)
544122205Sharti * Q.2971:Call-Control-N 11/39 (in N6)
545122205Sharti */
546122205Shartistatic void
547122205Shartiu1n6_call_proc(struct call *c, struct uni_msg *m, struct uni_all *u,
548122205Sharti    enum call_state new_state)
549122205Sharti{
550122205Sharti	struct uni_call_proc *cp = &u->u.call_proc;
551122205Sharti	struct uniapi_proceeding_indication *ind;
552122205Sharti	struct uni_msg *api;
553122205Sharti
554122205Sharti	ind = ALLOC_API(struct uniapi_proceeding_indication, api);
555122205Sharti	if (ind == NULL) {
556122205Sharti  ignore:
557122205Sharti		uni_msg_destroy(m);
558122205Sharti		UNI_FREE(u);
559122205Sharti		return;
560122205Sharti	}
561122205Sharti	/*
562122205Sharti	 * Analyze message
563122205Sharti	 */
564122205Sharti	(void)uni_decode_body(m, u, &c->uni->cx);
565122205Sharti	if (!IE_ISPRESENT(c->connid) && !IE_ISGOOD(cp->connid))
566122205Sharti		uni_mandate_ie(c->uni, UNI_IE_CONNID);
567122205Sharti
568122205Sharti	/*
569122205Sharti	 * Q.2971: L3MU_01_03 requests us to ignore the message if
570122205Sharti	 * the EPREF is missing.
571122205Sharti	 */
572122205Sharti	if (c->msg_setup.bearer.cfg == UNI_BEARER_MP &&
573122205Sharti	    IE_ISPRESENT(c->msg_setup.epref)) {
574122205Sharti		if (!IE_ISPRESENT(cp->epref))
575122205Sharti			uni_mandate_ie(c->uni, UNI_IE_EPREF);				\
576122205Sharti
577122205Sharti		else if (IE_ISGOOD(cp->epref) &&
578122205Sharti		    (cp->epref.flag != 1 ||
579122205Sharti		     cp->epref.epref != c->msg_setup.epref.epref)) {
580122205Sharti			IE_SETERROR(cp->epref);
581213789Srpaulo			(void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF,
582122205Sharti			    cp->epref.h.act, UNI_IERR_BAD);
583122205Sharti		}
584122205Sharti	}
585122205Sharti
586122205Sharti	switch (uni_verify(c->uni, u->u.hdr.act)) {
587122205Sharti
588122205Sharti	  case VFY_CLR:
589122205Sharti		uni_vfy_collect_ies(c->uni);
590122205Sharti		clear_callD(c);
591122205Sharti		/* FALLTHRU */
592122205Sharti	  case VFY_I:
593122205Sharti		uni_msg_destroy(api);
594122205Sharti		goto ignore;
595122205Sharti
596122205Sharti	  case VFY_RAIM:
597122205Sharti	  case VFY_RAI:
598122205Sharti	  report:
599122205Sharti		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
600122205Sharti		    map_callstate(c->cstate), NULL, 0);
601122205Sharti		uni_msg_destroy(api);
602122205Sharti		goto ignore;
603122205Sharti
604122205Sharti	  case VFY_RAP:
605122205Sharti	  case VFY_RAPU:
606122205Sharti		if (c->type == CALL_ROOT && !IE_ISGOOD(cp->epref))
607122205Sharti			goto report;
608122205Sharti		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
609122205Sharti		    map_callstate(new_state), NULL, 0);
610122205Sharti		/* FALLTHRU */
611122205Sharti	  case VFY_OK:
612122205Sharti		break;
613122205Sharti	}
614122205Sharti
615122205Sharti	TIMER_STOP_CALL(c, t303);
616122205Sharti
617122205Sharti	if (IE_ISGOOD(cp->connid))
618122205Sharti		c->connid = cp->connid;
619122205Sharti
620122205Sharti	ind->call_proc.hdr = u->u.hdr;
621122205Sharti	copy_msg_call_proc(cp, &ind->call_proc);
622122205Sharti	c->uni->funcs->uni_output(c->uni, c->uni->arg,
623122205Sharti	    UNIAPI_PROCEEDING_indication, 0, api);
624122205Sharti
625122205Sharti	TIMER_START_CALL(c, t310, c->uni->timer310);
626122205Sharti
627122205Sharti	uni_msg_destroy(m);
628122205Sharti	UNI_FREE(u);
629122205Sharti
630122205Sharti	set_call_state(c, new_state);
631122205Sharti}
632122205Sharti
633122205Sharti/*
634122205Sharti * T303 tick.
635122205Sharti *
636122205Sharti * Q.2971:Call-Control-U 6/39
637122205Sharti * Q.2971:Call-Control-N 11/39
638122205Sharti */
639122205Shartistatic void
640122205Shartiu1n6_t303(struct call *c)
641122205Sharti{
642122205Sharti	struct uni_all *msg;
643122205Sharti	struct uniapi_release_confirm *conf;
644122205Sharti	struct uni_msg *api;
645122205Sharti
646122205Sharti	VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T303 tick %d",
647122205Sharti	    c->cref, c->mine ? "mine" : "his", c->cnt303 + 1);
648122205Sharti
649122205Sharti	if (++c->cnt303 < c->uni->init303) {
650122205Sharti		if ((msg = UNI_ALLOC()) != NULL) {
651122205Sharti			msg->u.setup = c->msg_setup;
652122205Sharti			MK_MSG_ORIG(msg, UNI_SETUP, c->cref, !c->mine);
653122205Sharti			(void)uni_send_output(msg, c->uni);
654122205Sharti			UNI_FREE(msg);
655122205Sharti		}
656122205Sharti		TIMER_START_CALL(c, t303, c->uni->timer303);
657122205Sharti		return;
658122205Sharti	}
659122205Sharti
660122205Sharti	/*
661122205Sharti	 * Send indication to API
662122205Sharti	 */
663122205Sharti	if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) != NULL) {
664122205Sharti		conf->release.hdr.cref.cref = c->cref;
665122205Sharti		conf->release.hdr.cref.flag = c->mine;
666122205Sharti		conf->release.hdr.act = UNI_MSGACT_DEFAULT;
667122205Sharti		MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER,
668122205Sharti		    UNI_CAUSE_NO_RESPONSE);
669122205Sharti
670122205Sharti		c->uni->funcs->uni_output(c->uni, c->uni->arg,
671122205Sharti		    UNIAPI_RELEASE_confirm, 0, api);
672122205Sharti	}
673122205Sharti
674122205Sharti	/*
675122205Sharti	 * send to party (there may be only one)
676122205Sharti	 */
677122205Sharti	if (c->type == CALL_ROOT && !TAILQ_EMPTY(&c->parties)) {
678122205Sharti		uni_enq_party(TAILQ_FIRST(&c->parties),
679122205Sharti		    SIGP_RELEASE_confirm, 0, NULL, NULL);
680122205Sharti	}
681122205Sharti	uni_destroy_call(c, 0);
682122205Sharti}
683122205Sharti
684122205Sharti/*
685122205Sharti * T310 (Call Proceeding) timer tick.
686122205Sharti *
687122205Sharti * Q.2971:Call-Control-U 7/39
688122205Sharti * Q.2971:Call-Control-N 17/39
689122205Sharti */
690122205Shartistatic void
691122205Shartiu3n9_t310(struct call *c)
692122205Sharti{
693122205Sharti	VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T310 tick",
694122205Sharti	    c->cref, c->mine ? "mine" : "his");
695122205Sharti
696122205Sharti	MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_NO_RESPONSE);
697122205Sharti	clear_callD(c);
698122205Sharti}
699122205Sharti
700122205Sharti/*
701122205Sharti * T301 (Alerting) timer tick.
702122205Sharti *
703122205Sharti * Q.2971:Call-Control-U Missing
704122205Sharti * Q.2971:Call-Control-N 14/39
705122205Sharti */
706122205Shartistatic void
707122205Shartiu4n7_t301(struct call *c)
708122205Sharti{
709122205Sharti	VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T301 tick",
710122205Sharti	    c->cref, c->mine ? "mine" : "his");
711122205Sharti
712122205Sharti	MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_NO_RESP_ALERT);
713122205Sharti	clear_callD(c);
714122205Sharti}
715122205Sharti
716122205Sharti/*
717122205Sharti * ALERTING received
718122205Sharti *
719122205Sharti * Q.2971:Call-Control-U 37/39 (U1)
720122205Sharti * Q.2971:Call-Control-U 7/39 (U3)
721122205Sharti * Q.2971:Call-Control-N 9/39 (N6)
722122205Sharti * Q.2971:Call-Control-N 17/39 (N9)
723122205Sharti *
724122205Sharti * There are two errors in the user side SDL Annex A:
725122205Sharti *
726122205Sharti *   - the resetted timers are swapped (T310 and T303)
727122205Sharti *
728122205Sharti *   - for U1 we should go to C12, not C3 to start T301.
729122205Sharti */
730122205Shartistatic void
731122205Shartiunx_alerting(struct call *c, struct uni_msg *m, struct uni_all *u,
732122205Sharti    enum call_state new_state)
733122205Sharti{
734122205Sharti	struct uni_alerting *al = &u->u.alerting;
735122205Sharti	struct uniapi_alerting_indication *ind;
736122205Sharti	struct uni_msg *api;
737122205Sharti
738122205Sharti	ind = ALLOC_API(struct uniapi_alerting_indication, api);
739122205Sharti	if (ind == NULL) {
740122205Sharti  ignore:
741122205Sharti		uni_msg_destroy(m);
742122205Sharti		UNI_FREE(u);
743122205Sharti		return;
744122205Sharti	}
745122205Sharti
746122205Sharti	/*
747122205Sharti	 * Analyze message
748122205Sharti	 */
749122205Sharti	(void)uni_decode_body(m, u, &c->uni->cx);
750122205Sharti	if (!IE_ISPRESENT(c->connid) && !IE_ISGOOD(al->connid))
751122205Sharti		uni_mandate_ie(c->uni, UNI_IE_CONNID);
752122205Sharti
753122205Sharti	/*
754122205Sharti	 * Q.2971: L3MU_01_04 requests us to ignore the message if the
755122205Sharti	 * EPREF is missing.
756122205Sharti	 */
757122205Sharti	if (c->msg_setup.bearer.cfg == UNI_BEARER_MP &&
758122205Sharti	    IE_ISPRESENT(c->msg_setup.epref)) {
759122205Sharti		if (!IE_ISPRESENT(al->epref))
760122205Sharti			uni_mandate_ie(c->uni, UNI_IE_EPREF);				\
761122205Sharti
762122205Sharti		else if (IE_ISGOOD(al->epref) &&
763122205Sharti		    (al->epref.flag != 1 ||
764122205Sharti		     al->epref.epref != c->msg_setup.epref.epref)) {
765122205Sharti			IE_SETERROR(al->epref);
766213789Srpaulo			(void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF,
767122205Sharti			    al->epref.h.act, UNI_IERR_BAD);
768122205Sharti		}
769122205Sharti	}
770122205Sharti
771122205Sharti	switch (uni_verify(c->uni, u->u.hdr.act)) {
772122205Sharti
773122205Sharti	  case VFY_CLR:
774122205Sharti		uni_vfy_collect_ies(c->uni);
775122205Sharti		clear_callD(c);
776122205Sharti	  case VFY_I:
777122205Sharti		uni_msg_destroy(api);
778122205Sharti	  	goto ignore;
779122205Sharti
780122205Sharti	  case VFY_RAIM:
781122205Sharti	  case VFY_RAI:
782122205Sharti	  report:
783122205Sharti		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
784122205Sharti		    map_callstate(c->cstate), NULL, 0);
785122205Sharti		uni_msg_destroy(api);
786122205Sharti	  	goto ignore;
787122205Sharti
788122205Sharti	  case VFY_RAP:
789122205Sharti	  case VFY_RAPU:
790122205Sharti		if (c->type == CALL_ROOT && !IE_ISGOOD(al->epref))
791122205Sharti			goto report;
792122205Sharti		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
793122205Sharti		    map_callstate(c->cstate), NULL, 0);
794122205Sharti	  case VFY_OK:
795122205Sharti		break;
796122205Sharti	}
797122205Sharti
798122205Sharti	if (c->cstate == CALLST_U1 || c->cstate == CALLST_N6)
799122205Sharti		TIMER_STOP_CALL(c, t303);
800122205Sharti	else if (c->cstate == CALLST_U3 || c->cstate == CALLST_N9)
801122205Sharti		TIMER_STOP_CALL(c, t310);
802122205Sharti
803122205Sharti	if (IE_ISGOOD(al->connid))
804122205Sharti		c->connid = al->connid;
805122205Sharti
806122205Sharti	ind->alerting.hdr = u->u.hdr;
807122205Sharti	copy_msg_alerting(al, &ind->alerting);
808122205Sharti
809122205Sharti	if (c->type == CALL_LEAF || c->type == CALL_ROOT) {
810122205Sharti		uni_enq_party(TAILQ_FIRST(&c->parties), SIGP_ALERTING,
811122205Sharti		    0, NULL, NULL);
812122205Sharti		c->uni->funcs->uni_output(c->uni, c->uni->arg,
813122205Sharti		    UNIAPI_ALERTING_indication, 0, api);
814122205Sharti	} else {
815122205Sharti		c->uni->funcs->uni_output(c->uni, c->uni->arg,
816122205Sharti		    UNIAPI_ALERTING_indication, 0, api);
817122205Sharti		TIMER_START_CALL(c, t301, c->uni->timer301);
818122205Sharti	}
819122205Sharti	UNI_FREE(u);
820122205Sharti	uni_msg_destroy(m);
821122205Sharti
822122205Sharti	set_call_state(c, new_state);
823122205Sharti}
824122205Sharti
825122205Sharti/*
826122205Sharti * Proceeding.request from API
827122205Sharti *
828122205Sharti * Q.2971:Call-Control-U 12/39 (U6)
829122205Sharti * Q.2971:Call-Control-N 6/39 (N1)
830122205Sharti */
831122205Shartistatic void
832131826Shartiu6n1_proceeding_request(struct call *c, struct uni_msg *m, uint32_t cookie,
833122205Sharti    enum call_state new_state)
834122205Sharti{
835122205Sharti	struct uni_all *msg;
836122205Sharti	struct uniapi_proceeding_request *arg =
837122205Sharti	    uni_msg_rptr(m, struct uniapi_proceeding_request *);
838122205Sharti
839122205Sharti	if ((msg = UNI_ALLOC()) == NULL) {
840122205Sharti		uni_msg_destroy(m);
841122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
842122205Sharti		return;
843122205Sharti	}
844122205Sharti
845122205Sharti	if (IE_ISGOOD(arg->call_proc.connid))
846122205Sharti		c->connid = arg->call_proc.connid;
847122205Sharti
848122205Sharti	msg->u.call_proc = arg->call_proc;
849122205Sharti	MK_MSG_ORIG(msg, UNI_CALL_PROC, c->cref, !c->mine);
850122205Sharti	(void)uni_send_output(msg, c->uni);
851122205Sharti	UNI_FREE(msg);
852122205Sharti
853122205Sharti	set_call_state(c, new_state);
854122205Sharti
855122205Sharti	uni_msg_destroy(m);
856122205Sharti
857122205Sharti	uniapi_call_error(c, UNIAPI_OK, cookie);
858122205Sharti}
859122205Sharti
860122205Sharti/*
861122205Sharti * Alerting.request from API
862122205Sharti *
863122205Sharti * Q.2971:Call-Control-U 13/39 (U6)
864122205Sharti * Q.2971:Call-Control-U 17/39 (U9)
865122205Sharti * Q.2971:Call-Control-N 38/39 (N1)
866122205Sharti * Q.2971:Call-Control-N 7/39  (N3)
867122205Sharti */
868122205Shartistatic void
869131826Shartiunx_alerting_request(struct call *c, struct uni_msg *m, uint32_t cookie,
870122205Sharti    enum call_state new_state)
871122205Sharti{
872122205Sharti	struct uni_all *msg;
873122205Sharti	struct uniapi_alerting_request *arg =
874122205Sharti	    uni_msg_rptr(m, struct uniapi_alerting_request *);
875122205Sharti
876122205Sharti	if ((msg = UNI_ALLOC()) == NULL) {
877122205Sharti		uni_msg_destroy(m);
878122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
879122205Sharti		return;
880122205Sharti	}
881122205Sharti
882122205Sharti	if (c->type == CALL_ROOT || c->type == CALL_LEAF) {
883122205Sharti		uni_enq_party(TAILQ_FIRST(&c->parties),
884122205Sharti		    SIGP_ALERTING_request, cookie, NULL, NULL);
885122205Sharti	}
886122205Sharti
887122205Sharti	/*
888122205Sharti	 * It's not really clear, what happens, if we send another
889122205Sharti	 * connid in CALL_PROC and ALERTING
890122205Sharti	 */
891122205Sharti	if (!IE_ISGOOD(c->connid) && IE_ISGOOD(arg->alerting.connid))
892122205Sharti		c->connid = arg->alerting.connid;
893122205Sharti
894122205Sharti	msg->u.alerting = arg->alerting;
895122205Sharti	MK_MSG_ORIG(msg, UNI_ALERTING, c->cref, !c->mine);
896122205Sharti	(void)uni_send_output(msg, c->uni);
897122205Sharti	UNI_FREE(msg);
898122205Sharti
899122205Sharti	set_call_state(c, new_state);
900122205Sharti
901122205Sharti	uni_msg_destroy(m);
902122205Sharti
903122205Sharti	uniapi_call_error(c, UNIAPI_OK, cookie);
904122205Sharti}
905122205Sharti
906122205Sharti
907122205Sharti/*
908122205Sharti * Setup.response from API
909122205Sharti *
910122205Sharti * Q.2971:Call-Control-U 13/39	(U6)
911122205Sharti * Q.2971:Call-Control-U 14/39	(U7)
912122205Sharti * Q.2971:Call-Control-U 17/39	(U9)
913122205Sharti * Q.2971:Call-Control-N 39/39  (N1)
914122205Sharti * Q.2971:Call-Control-N 7/39   (N3)
915122205Sharti * Q.2971:Call-Control-N 8/39   (N4)
916122205Sharti */
917122205Shartistatic void
918131826Shartiunx_setup_response(struct call *c, struct uni_msg *m, uint32_t cookie,
919122205Sharti    enum call_state new_state)
920122205Sharti{
921122205Sharti	struct uni_all *msg;
922122205Sharti	struct uniapi_setup_response *arg =
923122205Sharti	    uni_msg_rptr(m, struct uniapi_setup_response *);
924122205Sharti	struct party *p;
925122205Sharti
926122205Sharti	if ((msg = UNI_ALLOC()) == NULL) {
927122205Sharti		uni_msg_destroy(m);
928122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
929122205Sharti		return;
930122205Sharti	}
931122205Sharti
932122205Sharti	if (!IE_ISGOOD(c->connid) && IE_ISGOOD(arg->connect.connid))
933122205Sharti		c->connid = arg->connect.connid;
934122205Sharti
935122205Sharti	if (IE_ISGOOD(arg->connect.epref)) {
936122205Sharti		p = uni_find_partyx(c, arg->connect.epref.epref,
937122205Sharti		    !arg->connect.epref.flag);
938122205Sharti		if (p == NULL) {
939122205Sharti			uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
940122205Sharti			UNI_FREE(msg);
941122205Sharti			uni_msg_destroy(m);
942122205Sharti			return;
943122205Sharti		}
944122205Sharti		/* we need to remember that we have sent the CONNECT from this
945122205Sharti		 * party because the CONNECT ACK must move only this party
946122205Sharti		 * into P7 */
947122205Sharti		p->flags |= PARTY_CONNECT;
948122205Sharti
949122205Sharti	} else if (c->type == CALL_LEAF) {
950131826Sharti		/* XXX don't mandate if only one party */
951122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
952122205Sharti		UNI_FREE(msg);
953122205Sharti		uni_msg_destroy(m);
954122205Sharti		return;
955122205Sharti	}
956122205Sharti
957122205Sharti	/* inform the parties on the network side */
958122205Sharti	if (c->uni->proto == UNIPROTO_UNI40N && c->type == CALL_LEAF)
959122205Sharti		TAILQ_FOREACH(p, &c->parties, link)
960122205Sharti			uni_enq_party(p, SIGP_SETUP_response, 0, NULL, NULL);
961122205Sharti
962122205Sharti	msg->u.connect = arg->connect;
963122205Sharti	MK_MSG_ORIG(msg, UNI_CONNECT, c->cref, !c->mine);
964122205Sharti	(void)uni_send_output(msg, c->uni);
965122205Sharti	UNI_FREE(msg);
966122205Sharti
967122205Sharti	if (c->uni->proto == UNIPROTO_UNI40U)
968122205Sharti		TIMER_START_CALL(c, t313, c->uni->timer313);
969122205Sharti
970122205Sharti	set_call_state(c, new_state);
971122205Sharti
972122205Sharti	uni_msg_destroy(m);
973122205Sharti
974122205Sharti	uniapi_call_error(c, UNIAPI_OK, cookie);
975122205Sharti}
976122205Sharti
977122205Sharti/*
978122205Sharti * Setup_complete.request
979122205Sharti *
980122205Sharti * Q.2971:Call-Control-N 15/39 (N8)
981122205Sharti */
982122205Shartistatic void
983131826Shartin8_setup_compl_request(struct call *c, struct uni_msg *m, uint32_t cookie,
984122205Sharti    enum call_state new_state)
985122205Sharti{
986122205Sharti	struct uni_all *msg;
987122205Sharti	struct uniapi_setup_complete_request *arg =
988122205Sharti	    uni_msg_rptr(m, struct uniapi_setup_complete_request *);
989122205Sharti	struct party *p;
990122205Sharti
991122205Sharti	if ((msg = UNI_ALLOC()) == NULL) {
992122205Sharti		uni_msg_destroy(m);
993122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
994122205Sharti		return;
995122205Sharti	}
996122205Sharti
997122205Sharti	/* inform the parties on the network side */
998122205Sharti	if (c->uni->proto == UNIPROTO_UNI40N &&
999122205Sharti	    (c->type == CALL_LEAF || c->type == CALL_ROOT)) {
1000122205Sharti		TAILQ_FOREACH(p, &c->parties, link)
1001122205Sharti			uni_enq_party(p, SIGP_SETUP_COMPL_request,
1002122205Sharti			    0, NULL, NULL);
1003122205Sharti	}
1004122205Sharti
1005122205Sharti	msg->u.connect_ack = arg->connect_ack;
1006122205Sharti	MK_MSG_ORIG(msg, UNI_CONNECT_ACK, c->cref, !c->mine);
1007122205Sharti	(void)uni_send_output(msg, c->uni);
1008122205Sharti	UNI_FREE(msg);
1009122205Sharti
1010122205Sharti	set_call_state(c, new_state);
1011122205Sharti
1012122205Sharti	uni_msg_destroy(m);
1013122205Sharti
1014122205Sharti	uniapi_call_error(c, UNIAPI_OK, cookie);
1015122205Sharti}
1016122205Sharti
1017122205Sharti/*
1018122205Sharti * CONNECT message
1019122205Sharti *
1020122205Sharti * Q.2971:Call-Control-U 7-8/39  (U3)
1021122205Sharti * Q.2971:Call-Control-U 11/39   (U4)
1022122205Sharti * Q.2971:Call-Control-U 37/39   (U1)
1023122205Sharti * Q.2971:Call-Control-N 9-10/39 (N6)
1024122205Sharti * Q.2971:Call-Control-N 14/39   (N7)
1025122205Sharti * Q.2971:Call-Control-N 17/39   (N9)
1026122205Sharti */
1027122205Shartistatic void
1028122205Shartiunx_connect(struct call *c, struct uni_msg *m, struct uni_all *u,
1029122205Sharti    enum call_state new_state)
1030122205Sharti{
1031122205Sharti	struct uni_connect *co = &u->u.connect;
1032122205Sharti	struct uniapi_setup_confirm *conf;
1033122205Sharti	struct uni_msg *api;
1034122205Sharti	struct uni_all *ack;
1035122205Sharti	struct party *p;
1036122205Sharti
1037122205Sharti	conf = ALLOC_API(struct uniapi_setup_confirm, api);
1038122205Sharti	if (conf == NULL) {
1039122205Sharti  ignore:
1040122205Sharti		UNI_FREE(u);
1041122205Sharti		uni_msg_destroy(m);
1042122205Sharti		return;
1043122205Sharti	}
1044122205Sharti	if ((ack = UNI_ALLOC()) == NULL) {
1045122205Sharti		uni_msg_destroy(api);
1046122205Sharti		goto ignore;
1047122205Sharti	}
1048122205Sharti
1049122205Sharti	/*
1050122205Sharti	 * Analyze message
1051122205Sharti	 */
1052122205Sharti	(void)uni_decode_body(m, u, &c->uni->cx);
1053122205Sharti	if (!IE_ISPRESENT(c->connid) && !IE_ISGOOD(co->connid))
1054122205Sharti		uni_mandate_ie(c->uni, UNI_IE_CONNID);
1055122205Sharti
1056122205Sharti	/*
1057122205Sharti	 * Q.2971: L3MU_01_05 requires the epref to be present.
1058122205Sharti	 */
1059122205Sharti	p = NULL;
1060122205Sharti	if (c->msg_setup.bearer.cfg == UNI_BEARER_MP) {
1061122205Sharti		if (IE_ISPRESENT(c->msg_setup.epref)) {
1062122205Sharti			if (!IE_ISPRESENT(co->epref))
1063122205Sharti				uni_mandate_ie(c->uni, UNI_IE_EPREF);				\
1064122205Sharti
1065122205Sharti			if (IE_ISGOOD(co->epref) &&
1066122205Sharti			    co->epref.flag != 1) {
1067122205Sharti				IE_SETERROR(co->epref);
1068213789Srpaulo				(void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF,
1069122205Sharti				    co->epref.h.act, UNI_IERR_BAD);
1070122205Sharti			}
1071122205Sharti		}
1072122205Sharti
1073122205Sharti		if (IE_ISGOOD(co->epref)) {
1074122205Sharti			p = uni_find_party(c, &co->epref);
1075122205Sharti			if (p == NULL) {
1076122205Sharti				respond_drop_party_ack(c, &co->epref,
1077122205Sharti				    UNI_CAUSE_ENDP_INV);
1078122205Sharti				uni_msg_destroy(api);
1079122205Sharti				UNI_FREE(ack);
1080122205Sharti				goto ignore;
1081122205Sharti			}
1082122205Sharti		}
1083122205Sharti	}
1084122205Sharti
1085122205Sharti	switch (uni_verify(c->uni, u->u.hdr.act)) {
1086122205Sharti
1087122205Sharti	  case VFY_CLR:
1088122205Sharti		uni_vfy_collect_ies(c->uni);
1089122205Sharti		clear_callD(c);
1090122205Sharti		/* FALLTHRU */
1091122205Sharti	  case VFY_I:
1092122205Sharti		uni_msg_destroy(api);
1093122205Sharti		UNI_FREE(ack);
1094122205Sharti	  	goto ignore;
1095122205Sharti
1096122205Sharti	  case VFY_RAIM:
1097122205Sharti	  case VFY_RAI:
1098122205Sharti	  report:
1099122205Sharti		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
1100122205Sharti		    map_callstate(c->cstate), NULL, 0);
1101122205Sharti		uni_msg_destroy(api);
1102122205Sharti		UNI_FREE(ack);
1103122205Sharti	  	goto ignore;
1104122205Sharti
1105122205Sharti	  case VFY_RAP:
1106122205Sharti	  case VFY_RAPU:
1107122205Sharti		if (c->type == CALL_ROOT && !IE_ISGOOD(co->epref))
1108122205Sharti			goto report;
1109122205Sharti		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
1110122205Sharti		    map_callstate(new_state), NULL, 0);
1111122205Sharti		/* FALLTHRU */
1112122205Sharti	  case VFY_OK:
1113122205Sharti		break;
1114122205Sharti	}
1115122205Sharti
1116122205Sharti	if (IE_ISGOOD(co->connid))
1117122205Sharti		c->connid = co->connid;
1118122205Sharti
1119122205Sharti	if (c->cstate == CALLST_U1 || c->cstate == CALLST_N6)
1120122205Sharti		TIMER_STOP_CALL(c, t303);
1121122205Sharti	else if (c->cstate == CALLST_U3 || c->cstate == CALLST_N9)
1122122205Sharti		TIMER_STOP_CALL(c, t310);
1123122205Sharti	else if (c->cstate == CALLST_U4 || c->cstate == CALLST_N7) {
1124122205Sharti		if(c->type == CALL_P2P)
1125122205Sharti			TIMER_STOP_CALL(c, t301);
1126122205Sharti	}
1127122205Sharti
1128122205Sharti	/*
1129122205Sharti	 * This is sent to the party only on the user side and only
1130122205Sharti	 * to the one party in the epref (L3MU_05_03).
1131122205Sharti	 */
1132122205Sharti	if (c->uni->proto == UNIPROTO_UNI40U &&
1133122205Sharti	    (c->type == CALL_LEAF || c->type == CALL_ROOT))
1134122205Sharti		uni_enq_party(p, SIGP_CONNECT, 0, NULL, NULL);
1135122205Sharti
1136122205Sharti	conf->connect.hdr = u->u.hdr;
1137122205Sharti	copy_msg_connect(co, &conf->connect);
1138122205Sharti	c->uni->funcs->uni_output(c->uni, c->uni->arg,
1139122205Sharti	    UNIAPI_SETUP_confirm, 0, api);
1140122205Sharti
1141122205Sharti	if (c->uni->proto == UNIPROTO_UNI40U) {
1142122205Sharti		/* this is left to the application on the network side */
1143122205Sharti		MK_MSG_ORIG(ack, UNI_CONNECT_ACK, c->cref, !c->mine);
1144122205Sharti		(void)uni_send_output(ack, c->uni);
1145122205Sharti		UNI_FREE(ack);
1146122205Sharti	}
1147122205Sharti
1148122205Sharti	UNI_FREE(u);
1149122205Sharti	uni_msg_destroy(m);
1150122205Sharti
1151122205Sharti	set_call_state(c, new_state);
1152122205Sharti}
1153122205Sharti
1154122205Sharti/*
1155122205Sharti * T313 (Connect) timer tick.
1156122205Sharti *
1157122205Sharti * Q.2971:Call-Control-U 15/39
1158122205Sharti */
1159122205Shartistatic void
1160122205Shartiu8_t313(struct call *c)
1161122205Sharti{
1162122205Sharti	VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T313 tick",
1163122205Sharti	    c->cref, c->mine ? "mine" : "his");
1164122205Sharti
1165122205Sharti	MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_RECOVER);
1166122205Sharti	ADD_CAUSE_TIMER(c->uni->cause, "313");
1167122205Sharti	clear_callD(c);
1168122205Sharti}
1169122205Sharti
1170122205Sharti/*
1171122205Sharti * CONNECT ACKNOWLEDGE message in U8
1172122205Sharti *
1173122205Sharti * Q.2971:Call-Control-U 15-16/39
1174122205Sharti */
1175122205Shartistatic void
1176122205Shartiu8_connect_ack(struct call *c, struct uni_msg *m, struct uni_all *u,
1177122205Sharti    enum call_state new_state)
1178122205Sharti{
1179122205Sharti	struct uniapi_setup_complete_indication *ind;
1180122205Sharti	struct uni_msg *api;
1181122205Sharti
1182122205Sharti	ind = ALLOC_API(struct uniapi_setup_complete_indication, api);
1183122205Sharti	if (ind == NULL) {
1184122205Sharti  ignore:
1185122205Sharti		uni_msg_destroy(m);
1186122205Sharti		UNI_FREE(u);
1187122205Sharti		return;
1188122205Sharti	}
1189122205Sharti
1190122205Sharti	/*
1191122205Sharti	 * Analyze message
1192122205Sharti	 */
1193122205Sharti	(void)uni_decode_body(m, u, &c->uni->cx);
1194122205Sharti
1195122205Sharti	switch (uni_verify(c->uni, u->u.hdr.act)) {
1196122205Sharti
1197122205Sharti	  case VFY_CLR:
1198122205Sharti		uni_vfy_collect_ies(c->uni);
1199122205Sharti		clear_callD(c);
1200122205Sharti		/* FALLTHRU */
1201122205Sharti	  case VFY_I:
1202122205Sharti		uni_msg_destroy(api);
1203122205Sharti	  	goto ignore;
1204122205Sharti
1205122205Sharti	  case VFY_RAIM:
1206122205Sharti	  case VFY_RAI:
1207122205Sharti		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
1208122205Sharti		    map_callstate(c->cstate), NULL, 0);
1209122205Sharti		uni_msg_destroy(api);
1210122205Sharti	  	goto ignore;
1211122205Sharti
1212122205Sharti	  case VFY_RAP:
1213122205Sharti	  case VFY_RAPU:
1214122205Sharti		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
1215122205Sharti		    map_callstate(new_state), NULL, 0);
1216122205Sharti		/* FALLTHRU */
1217122205Sharti	  case VFY_OK:
1218122205Sharti		break;
1219122205Sharti	}
1220122205Sharti
1221122205Sharti	TIMER_STOP_CALL(c, t313);
1222122205Sharti
1223122205Sharti	if (c->type == CALL_LEAF) {
1224122205Sharti		struct party *p;
1225122205Sharti
1226122205Sharti		TAILQ_FOREACH(p, &c->parties, link) {
1227122205Sharti			if (p->flags & PARTY_CONNECT) {
1228122205Sharti				uni_enq_party(p, SIGP_CONNECT_ACK,
1229122205Sharti				    0, NULL, NULL);
1230122205Sharti				break;
1231122205Sharti			}
1232122205Sharti		}
1233122205Sharti	}
1234122205Sharti
1235122205Sharti	ind->connect_ack.hdr = u->u.hdr;
1236122205Sharti	copy_msg_connect_ack(&u->u.connect_ack, &ind->connect_ack);
1237122205Sharti	c->uni->funcs->uni_output(c->uni, c->uni->arg,
1238122205Sharti	    UNIAPI_SETUP_COMPLETE_indication, 0, api);
1239122205Sharti
1240122205Sharti	UNI_FREE(u);
1241122205Sharti	uni_msg_destroy(m);
1242122205Sharti
1243122205Sharti	set_call_state(c, new_state);
1244122205Sharti}
1245122205Sharti
1246122205Sharti/*
1247122205Sharti * CONNECT ACKNOWLEDGE message in N10
1248122205Sharti *
1249122205Sharti * Q.2971:Call-Control-N 18/39
1250122205Sharti */
1251122205Shartistatic void
1252122205Shartin10_connect_ack(struct call *c, struct uni_msg *m, struct uni_all *u)
1253122205Sharti{
1254122205Sharti	/*
1255122205Sharti	 * Analyze message
1256122205Sharti	 */
1257122205Sharti	(void)uni_decode_body(m, u, &c->uni->cx);
1258122205Sharti
1259122205Sharti	switch (uni_verify(c->uni, u->u.hdr.act)) {
1260122205Sharti
1261122205Sharti	  case VFY_CLR:
1262122205Sharti		uni_vfy_collect_ies(c->uni);
1263122205Sharti		clear_callD(c);
1264122205Sharti		/* FALLTHRU */
1265122205Sharti	  case VFY_I:
1266122205Sharti		uni_msg_destroy(m);
1267122205Sharti		UNI_FREE(u);
1268122205Sharti	  	return;
1269122205Sharti
1270122205Sharti	  case VFY_RAIM:
1271122205Sharti	  case VFY_RAI:
1272122205Sharti	  case VFY_RAP:
1273122205Sharti	  case VFY_RAPU:
1274122205Sharti		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
1275122205Sharti		    map_callstate(c->cstate), NULL, 0);
1276122205Sharti		/* FALLTHRU */
1277122205Sharti	  case VFY_OK:
1278122205Sharti		uni_msg_destroy(m);
1279122205Sharti		UNI_FREE(u);
1280122205Sharti	  	return;
1281122205Sharti	}
1282122205Sharti}
1283122205Sharti
1284122205Sharti/*
1285122205Sharti * Release.response in U6 or U12.
1286122205Sharti *
1287122205Sharti * Q.2971:Call-Control-U 12/39 (U6)
1288122205Sharti * Q.2971:Call-Control-U 30/39 (U12)
1289122205Sharti * Q.2971:Call-Control-N 6/39  (N1)
1290122205Sharti * Q.2971:Call-Control-N 29/39 (N11)
1291122205Sharti */
1292122205Shartistatic void
1293131826Shartiunx_release_response(struct call *c, struct uni_msg *m, uint32_t cookie)
1294122205Sharti{
1295122205Sharti	struct party *p;
1296122205Sharti	struct uni_all *msg;
1297122205Sharti	struct uniapi_release_response *arg =
1298122205Sharti	    uni_msg_rptr(m, struct uniapi_release_response *);
1299122205Sharti
1300122205Sharti	if ((msg = UNI_ALLOC()) == NULL) {
1301122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
1302122205Sharti		uni_msg_destroy(m);
1303122205Sharti		return;
1304122205Sharti	}
1305122205Sharti
1306122205Sharti	if (c->cstate == CALLST_U6 || c->cstate == CALLST_N1) {
1307122205Sharti		if (c->type == CALL_ROOT || c->type == CALL_LEAF) {
1308122205Sharti			TAILQ_FOREACH(p, &c->parties, link)
1309122205Sharti				uni_enq_party(p, SIGP_RELEASE_response,
1310122205Sharti				   cookie, NULL, NULL);
1311122205Sharti		}
1312122205Sharti	}
1313122205Sharti	msg->u.release_compl = arg->release_compl;
1314122205Sharti	MK_MSG_ORIG(msg, UNI_RELEASE_COMPL, c->cref, !c->mine);
1315122205Sharti	(void)uni_send_output(msg, c->uni);
1316122205Sharti	UNI_FREE(msg);
1317122205Sharti
1318122205Sharti	uni_msg_destroy(m);
1319122205Sharti
1320122205Sharti	uniapi_call_error(c, UNIAPI_OK, cookie);
1321122205Sharti
1322122205Sharti	uni_destroy_call(c, 0);
1323122205Sharti}
1324122205Sharti
1325122205Sharti/*
1326122205Sharti * Got a RELEASE COMPLETE in any state expect U0
1327122205Sharti *
1328122205Sharti * Q.2971:Call-Control-U 25/39
1329122205Sharti * Q.2971:Call-Control-N 26/39
1330122205Sharti *
1331122205Sharti * This is also called from the restart processes.
1332122205Sharti */
1333122205Shartivoid
1334122205Shartiuni_release_compl(struct call *c, struct uni_all *u)
1335122205Sharti{
1336122205Sharti	struct uni_msg *api;
1337122205Sharti	struct uniapi_release_confirm *conf;
1338122205Sharti	struct party *p;
1339122205Sharti	u_int i, j;
1340122205Sharti
1341122205Sharti	if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) == NULL)
1342122205Sharti		return;
1343122205Sharti
1344122205Sharti	reset_all_timers(c);
1345122205Sharti	if (c->type == CALL_ROOT || c->type == CALL_LEAF) {
1346122205Sharti		TAILQ_FOREACH(p, &c->parties, link)
1347122205Sharti			uni_enq_party(p, SIGP_RELEASE_COMPL, 0, NULL, NULL);
1348122205Sharti		/* YYY optional call reoffering 10.3.3/10.3.4 */
1349122205Sharti	}
1350122205Sharti	conf->release.hdr = u->u.hdr;
1351122205Sharti
1352122205Sharti	for (i = j = 0; i < 2; i++)
1353122205Sharti		if (IE_ISGOOD(u->u.release_compl.cause[i]))
1354122205Sharti			conf->release.cause[j++] = u->u.release_compl.cause[i];
1355122205Sharti	for (i = j = 0; i < UNI_NUM_IE_GIT; i++)
1356122205Sharti		if (IE_ISGOOD(u->u.release_compl.git[i]))
1357122205Sharti			conf->release.git[j++] = u->u.release_compl.git[i];
1358122205Sharti	if (IE_ISGOOD(u->u.release_compl.uu))
1359122205Sharti		conf->release.uu = u->u.release_compl.uu;
1360122205Sharti	if (IE_ISGOOD(u->u.release_compl.crankback))
1361122205Sharti		conf->release.crankback = u->u.release_compl.crankback;
1362122205Sharti
1363122205Sharti	c->uni->funcs->uni_output(c->uni, c->uni->arg,
1364122205Sharti	    UNIAPI_RELEASE_confirm, 0, api);
1365122205Sharti
1366122205Sharti	uni_destroy_call(c, 0);
1367122205Sharti}
1368122205Shartistatic void
1369122205Shartiunx_release_compl(struct call *c, struct uni_msg *m, struct uni_all *u)
1370122205Sharti{
1371122205Sharti
1372122205Sharti	(void)uni_decode_body(m, u, &c->uni->cx);
1373122205Sharti	(void)uni_verify(c->uni, u->u.hdr.act);	/* no point :-) */
1374122205Sharti
1375122205Sharti	uni_release_compl(c, u);
1376122205Sharti
1377122205Sharti	uni_msg_destroy(m);
1378122205Sharti	UNI_FREE(u);
1379122205Sharti}
1380122205Sharti
1381122205Sharti/*
1382122205Sharti * Got a RELEASE COMPLETE in any state expect U0 and U11
1383122205Sharti *
1384122205Sharti * Q.2971:Call-Control-U 25/39
1385122205Sharti * Q.2971:Call-Control-N 26/39
1386122205Sharti */
1387122205Shartistatic void
1388122205Shartiunx_release(struct call *c, struct uni_msg *m, struct uni_all *u,
1389122205Sharti    enum call_state new_state)
1390122205Sharti{
1391122205Sharti	struct uniapi_release_indication *ind;
1392122205Sharti	struct uni_msg *api;
1393122205Sharti
1394122205Sharti	if ((ind = ALLOC_API(struct uniapi_release_indication, api)) == NULL) {
1395122205Sharti		uni_msg_destroy(m);
1396122205Sharti		UNI_FREE(u);
1397122205Sharti		return;
1398122205Sharti	}
1399122205Sharti
1400122205Sharti	(void)uni_decode_body(m, u, &c->uni->cx);
1401122205Sharti	(void)uni_verify(c->uni, u->u.hdr.act);	/* no point :-) */
1402122205Sharti
1403122205Sharti	reset_all_timers(c);
1404122205Sharti	if (c->type == CALL_ROOT || c->type == CALL_LEAF) {
1405122205Sharti		struct party *p;
1406122205Sharti
1407122205Sharti		TAILQ_FOREACH(p, &c->parties, link)
1408122205Sharti			uni_enq_party(p, SIGP_RELEASE, 0, NULL, NULL);
1409122205Sharti		/* YYY optional call reoffering 10.3.3/10.3.4 */
1410122205Sharti	}
1411122205Sharti	if (c->cstate != new_state) {
1412122205Sharti		/*
1413122205Sharti		 * According to Q.2971 we should send a 2nd
1414122205Sharti		 * Release.indication.
1415122205Sharti		 * According to Q.2931 the recipte of a RELEASE in U12/N11
1416122205Sharti		 * is illegal.
1417122205Sharti		 * According to us make it legal, but don't send a 2nd
1418122205Sharti		 * indication.
1419122205Sharti		 */
1420122205Sharti		ind->release.hdr = u->u.hdr;
1421122205Sharti		copy_msg_release(&u->u.release, &ind->release);
1422122205Sharti
1423122205Sharti		c->uni->funcs->uni_output(c->uni, c->uni->arg,
1424122205Sharti		    UNIAPI_RELEASE_indication, 0, api);
1425122205Sharti	} else
1426122205Sharti		uni_msg_destroy(api);
1427122205Sharti
1428122205Sharti	uni_msg_destroy(m);
1429122205Sharti	UNI_FREE(u);
1430122205Sharti
1431122205Sharti	set_call_state(c, new_state);
1432122205Sharti}
1433122205Sharti
1434122205Sharti/*
1435122205Sharti * Got RELEASE in U11 or N12
1436122205Sharti *
1437122205Sharti * Q.2971:Call-Control-U 28/39
1438122205Sharti * Q.2971:Call-Control-N 30/39
1439122205Sharti */
1440122205Shartistatic void
1441122205Shartiu11n12_release(struct call *c, struct uni_msg *m, struct uni_all *u)
1442122205Sharti{
1443122205Sharti	struct uniapi_release_confirm *conf;
1444122205Sharti	struct uni_msg *api;
1445122205Sharti
1446122205Sharti	if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) == NULL) {
1447122205Sharti		uni_msg_destroy(m);
1448122205Sharti		UNI_FREE(u);
1449122205Sharti		return;
1450122205Sharti	}
1451122205Sharti
1452122205Sharti	(void)uni_decode_body(m, u, &c->uni->cx);
1453122205Sharti	(void)uni_verify(c->uni, u->u.hdr.act);	/* no point :-) */
1454122205Sharti
1455122205Sharti	TIMER_STOP_CALL(c, t308);
1456122205Sharti
1457122205Sharti	conf->release.hdr = u->u.hdr;
1458122205Sharti	copy_msg_release(&u->u.release, &conf->release);
1459122205Sharti
1460122205Sharti	c->uni->funcs->uni_output(c->uni, c->uni->arg,
1461122205Sharti	    UNIAPI_RELEASE_confirm, 0, api);
1462122205Sharti
1463122205Sharti	uni_msg_destroy(m);
1464122205Sharti	UNI_FREE(u);
1465122205Sharti
1466122205Sharti	uni_destroy_call(c, 0);
1467122205Sharti}
1468122205Sharti
1469122205Sharti/*
1470122205Sharti * NOTIFY message
1471122205Sharti *
1472122205Sharti * Q.2971:Call-Control-U 18/39
1473122205Sharti * Q.2971:Call-Control-N 19/39
1474122205Sharti */
1475122205Shartistatic void
1476122205Shartiunx_notify(struct call *c, struct uni_msg *m, struct uni_all *u)
1477122205Sharti{
1478122205Sharti	struct uniapi_notify_indication *ind;
1479122205Sharti	struct uni_msg *api;
1480122205Sharti	struct party *p = NULL;
1481122205Sharti
1482122205Sharti	if ((ind = ALLOC_API(struct uniapi_notify_indication, api)) == NULL) {
1483122205Sharti  ignore:
1484122205Sharti		uni_msg_destroy(m);
1485122205Sharti		UNI_FREE(u);
1486122205Sharti		return;
1487122205Sharti	}
1488122205Sharti
1489122205Sharti	/*
1490122205Sharti	 * Analyze message
1491122205Sharti	 */
1492122205Sharti	(void)uni_decode_body(m, u, &c->uni->cx);
1493122205Sharti	MANDATE_IE(c->uni, u->u.notify.notify, UNI_IE_NOTIFY);
1494122205Sharti
1495122205Sharti	if (IE_ISGOOD(u->u.notify.epref)) {
1496122205Sharti		if ((p = uni_find_party(c, &u->u.notify.epref)) == NULL) {
1497122205Sharti			respond_drop_party_ack(c, &u->u.notify.epref,
1498122205Sharti			    UNI_CAUSE_ENDP_INV);
1499122205Sharti			uni_msg_destroy(api);
1500122205Sharti			goto ignore;
1501122205Sharti		}
1502122205Sharti	}
1503122205Sharti
1504122205Sharti	switch (uni_verify(c->uni, u->u.hdr.act)) {
1505122205Sharti
1506122205Sharti	  case VFY_CLR:
1507122205Sharti		uni_msg_destroy(api);
1508122205Sharti		uni_vfy_collect_ies(c->uni);
1509122205Sharti		clear_callD(c);
1510122205Sharti	  	goto ignore;
1511122205Sharti
1512122205Sharti	  case VFY_RAIM:
1513122205Sharti	  case VFY_RAI:
1514122205Sharti		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
1515122205Sharti		    map_callstate(c->cstate), &u->u.notify.epref,
1516122205Sharti		    p ? p->state : 0);
1517122205Sharti		/* FALLTHRU */
1518122205Sharti	  case VFY_I:
1519122205Sharti		uni_msg_destroy(api);
1520122205Sharti	  	goto ignore;
1521122205Sharti
1522122205Sharti	  case VFY_RAP:
1523122205Sharti	  case VFY_RAPU:
1524122205Sharti		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
1525122205Sharti		    map_callstate(c->cstate), &u->u.notify.epref,
1526122205Sharti		    p ? p->state : 0);
1527122205Sharti	  case VFY_OK:
1528122205Sharti		/* FALLTHRU */
1529122205Sharti	  	break;
1530122205Sharti	}
1531122205Sharti
1532122205Sharti	ind->notify.hdr = u->u.hdr;
1533122205Sharti	copy_msg_notify(&u->u.notify, &ind->notify);
1534122205Sharti	c->uni->funcs->uni_output(c->uni, c->uni->arg,
1535122205Sharti	    UNIAPI_NOTIFY_indication, 0, api);
1536122205Sharti
1537122205Sharti	UNI_FREE(u);
1538122205Sharti	uni_msg_destroy(m);
1539122205Sharti}
1540122205Sharti
1541122205Sharti/*
1542122205Sharti * Notify.request from user
1543122205Sharti *
1544122205Sharti * Q.2971:Call-Control-U 18/39
1545122205Sharti * Q.2971:Call-Control-N 19/39
1546122205Sharti */
1547122205Shartistatic void
1548131826Shartiunx_notify_request(struct call *c, struct uni_msg *m, uint32_t cookie)
1549122205Sharti{
1550122205Sharti	struct uni_all *msg;
1551122205Sharti	struct uniapi_notify_request *arg =
1552122205Sharti	    uni_msg_rptr(m, struct uniapi_notify_request *);
1553122205Sharti
1554122205Sharti	if ((msg = UNI_ALLOC()) == NULL) {
1555122205Sharti		uni_msg_destroy(m);
1556122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
1557122205Sharti		return;
1558122205Sharti	}
1559122205Sharti
1560122205Sharti	msg->u.notify = arg->notify;
1561122205Sharti	MK_MSG_ORIG(msg, UNI_NOTIFY, c->cref, !c->mine);
1562122205Sharti	(void)uni_send_output(msg, c->uni);
1563122205Sharti	UNI_FREE(msg);
1564122205Sharti
1565122205Sharti	uni_msg_destroy(m);
1566122205Sharti
1567122205Sharti	uniapi_call_error(c, UNIAPI_OK, cookie);
1568122205Sharti}
1569122205Sharti
1570122205Sharti/**********************************************************************/
1571122205Sharti
1572122205Sharti/*
1573122205Sharti * Release.request from API in any state except U11, U12, N11, N12
1574122205Sharti *
1575122205Sharti * Q.2971:Call-Control-U 27/39
1576122205Sharti * Q.2971:Call-Control-N 28/39
1577122205Sharti */
1578122205Shartistatic void
1579131826Shartiunx_release_request(struct call *c, struct uni_msg *m, uint32_t cookie,
1580122205Sharti    enum call_state new_state)
1581122205Sharti{
1582122205Sharti	struct uni_all *msg;
1583122205Sharti	struct uniapi_release_request *arg =
1584122205Sharti	    uni_msg_rptr(m, struct uniapi_release_request *);
1585122205Sharti	struct party *p;
1586122205Sharti
1587122205Sharti	if ((msg = UNI_ALLOC()) == NULL) {
1588122205Sharti		uni_msg_destroy(m);
1589122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
1590122205Sharti		return;
1591122205Sharti	}
1592122205Sharti
1593122205Sharti	reset_all_timers(c);
1594122205Sharti
1595122205Sharti	if (c->type == CALL_LEAF || c->type == CALL_ROOT) {
1596122205Sharti		TAILQ_FOREACH(p, &c->parties, link) {
1597122205Sharti			uni_enq_party(p, SIGP_RELEASE_request, cookie,
1598122205Sharti			    NULL, NULL);
1599122205Sharti		}
1600122205Sharti	}
1601122205Sharti
1602122205Sharti	c->msg_release = arg->release;
1603122205Sharti	if (!IE_ISPRESENT(c->msg_release.cause[0]) &&
1604122205Sharti	    !IE_ISPRESENT(c->msg_release.cause[1]))
1605122205Sharti		MK_IE_CAUSE(c->msg_release.cause[0], UNI_CAUSE_LOC_USER,
1606122205Sharti		    UNI_CAUSE_UNSPEC);
1607122205Sharti
1608122205Sharti	msg->u.release = c->msg_release;
1609122205Sharti	MK_MSG_ORIG(msg, UNI_RELEASE, c->cref, !c->mine);
1610122205Sharti	(void)uni_send_output(msg, c->uni);
1611122205Sharti	UNI_FREE(msg);
1612122205Sharti
1613122205Sharti	TIMER_START_CALL(c, t308, c->uni->timer308);
1614122205Sharti	c->cnt308 = 0;
1615122205Sharti
1616122205Sharti	set_call_state(c, new_state);
1617122205Sharti
1618122205Sharti	uni_msg_destroy(m);
1619122205Sharti
1620122205Sharti	uniapi_call_error(c, UNIAPI_OK, cookie);
1621122205Sharti}
1622122205Sharti
1623122205Sharti/*
1624122205Sharti * Message with unknown EPREF - send a drop party according to 9.5.3.2.3a)
1625122205Sharti */
1626122205Shartistatic void
1627122205Shartirespond_drop_party_ack(struct call *c, struct uni_ie_epref *epref,
1628122205Sharti    u_int cause)
1629122205Sharti{
1630122205Sharti	struct uni_all *msg;
1631122205Sharti
1632122205Sharti	if ((msg = UNI_ALLOC()) == NULL)
1633122205Sharti		return;
1634122205Sharti
1635122205Sharti	MK_MSG_ORIG(msg, UNI_DROP_PARTY_ACK, c->cref, !c->mine);
1636122205Sharti	MK_IE_EPREF(msg->u.drop_party_ack.epref, epref->epref, !epref->flag);
1637122205Sharti	MK_IE_CAUSE(msg->u.drop_party_ack.cause, UNI_CAUSE_LOC_USER, cause);
1638122205Sharti	(void)uni_send_output(msg, c->uni);
1639122205Sharti	UNI_FREE(msg);
1640122205Sharti}
1641122205Sharti
1642122205Sharti/*
1643122205Sharti * T308 (RELEASE) timer
1644122205Sharti *
1645122205Sharti * Q.2971:Call-Control-U 28/39
1646122205Sharti * Q.2971:Call-Control-N 30/39
1647122205Sharti */
1648122205Shartistatic void
1649122205Shartiu11n12_t308(struct call *c)
1650122205Sharti{
1651122205Sharti	struct uni_all *msg;
1652122205Sharti	struct uni_msg *api;
1653122205Sharti	struct uniapi_release_confirm *conf;
1654122205Sharti
1655122205Sharti	VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T308 tick %d",
1656122205Sharti	    c->cref, c->mine ? "mine" : "his", c->cnt308 + 1);
1657122205Sharti
1658122205Sharti	if (++c->cnt308 < c->uni->init308) {
1659122205Sharti		if ((msg = UNI_ALLOC()) != NULL) {
1660122205Sharti			msg->u.release = c->msg_release;
1661122205Sharti			MK_MSG_ORIG(msg, UNI_RELEASE, c->cref, !c->mine);
1662122205Sharti			if (!IE_ISPRESENT(msg->u.release.cause[1])) {
1663122205Sharti				MK_IE_CAUSE(msg->u.release.cause[1],
1664122205Sharti				    UNI_CAUSE_LOC_USER, UNI_CAUSE_RECOVER);
1665122205Sharti				ADD_CAUSE_TIMER(msg->u.release.cause[1], "308");
1666122205Sharti			}
1667122205Sharti			(void)uni_send_output(msg, c->uni);
1668122205Sharti			UNI_FREE(msg);
1669122205Sharti		}
1670122205Sharti		TIMER_START_CALL(c, t308, c->uni->timer308);
1671122205Sharti		return;
1672122205Sharti	}
1673122205Sharti
1674122205Sharti	/*
1675122205Sharti	 * Send indication to API
1676122205Sharti	 */
1677122205Sharti	if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) != NULL) {
1678122205Sharti		conf->release.hdr.cref.cref = c->cref;
1679122205Sharti		conf->release.hdr.cref.flag = c->mine;
1680122205Sharti		conf->release.hdr.act = UNI_MSGACT_DEFAULT;
1681122205Sharti		MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER,
1682122205Sharti		    UNI_CAUSE_RECOVER);
1683122205Sharti		ADD_CAUSE_TIMER(conf->release.cause[0], "308");
1684122205Sharti
1685122205Sharti		c->uni->funcs->uni_output(c->uni, c->uni->arg,
1686122205Sharti		    UNIAPI_RELEASE_confirm, 0, api);
1687122205Sharti	}
1688122205Sharti
1689122205Sharti	uni_destroy_call(c, 0);
1690122205Sharti}
1691122205Sharti/**********************************************************************/
1692122205Sharti
1693122205Sharti/*
1694122205Sharti * STATUS in U11/U12
1695122205Sharti *
1696122205Sharti * Q.2971:Call-Control-U 29/39 (U11)
1697122205Sharti * Q.2971:Call-Control-U 30/39 (U12)
1698122205Sharti * Q.2971:Call-Control-N 29/39 (N11)
1699122205Sharti * Q.2971:Call-Control-N 31/39 (N12)
1700122205Sharti */
1701122205Shartistatic void
1702122205Shartiun11un12_status(struct call *c, struct uni_msg *m, struct uni_all *u)
1703122205Sharti{
1704122205Sharti	enum call_state ns;
1705122205Sharti	struct uniapi_release_confirm *conf;
1706122205Sharti	struct uni_msg *api;
1707122205Sharti	struct party *p;
1708122205Sharti	struct uniapi_status_indication *stat;
1709122205Sharti
1710122205Sharti	/*
1711122205Sharti	 * Analyze message
1712122205Sharti	 */
1713122205Sharti	(void)uni_decode_body(m, u, &c->uni->cx);
1714122205Sharti	MANDATE_IE(c->uni, u->u.status.callstate, UNI_IE_CALLSTATE);
1715122205Sharti	MANDATE_IE(c->uni, u->u.status.cause, UNI_IE_CAUSE);
1716122205Sharti
1717122205Sharti	ns = c->cstate;
1718122205Sharti	if (IE_ISGOOD(u->u.status.callstate) &&
1719122205Sharti	    u->u.status.callstate.state == UNI_CALLSTATE_U0)
1720122205Sharti		ns = CALLST_NULL;
1721122205Sharti
1722122205Sharti	p = NULL;
1723122205Sharti	if (IE_ISGOOD(u->u.status.epref))
1724122205Sharti		p = uni_find_party(c, &u->u.status.epref);
1725122205Sharti
1726122205Sharti	switch (uni_verify(c->uni, u->u.hdr.act)) {
1727122205Sharti
1728122205Sharti	  case VFY_CLR:
1729122205Sharti		uni_vfy_collect_ies(c->uni);
1730122205Sharti		clear_callD(c);
1731122205Sharti		uni_msg_destroy(m);
1732122205Sharti		UNI_FREE(u);
1733122205Sharti	  	return;
1734122205Sharti
1735122205Sharti	  case VFY_RAIM:
1736122205Sharti	  case VFY_RAI:
1737122205Sharti	  case VFY_RAP:
1738122205Sharti	  case VFY_RAPU:
1739122205Sharti		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
1740122205Sharti		    map_callstate(ns), &u->u.status.epref,
1741122205Sharti		    p ? p->state : UNI_EPSTATE_NULL);
1742122205Sharti	  case VFY_I:
1743122205Sharti	  case VFY_OK:
1744122205Sharti	  	break;
1745122205Sharti	}
1746122205Sharti
1747122205Sharti	if (ns == c->cstate) {
1748122205Sharti		/*
1749122205Sharti		 * Inform API
1750122205Sharti		 */
1751122205Sharti		stat = ALLOC_API(struct uniapi_status_indication, api);
1752122205Sharti		if (stat != NULL) {
1753122205Sharti			stat->cref = u->u.hdr.cref;
1754122205Sharti			stat->my_state = map_callstate(c->cstate);
1755122205Sharti			stat->his_state = u->u.status.callstate;
1756122205Sharti			stat->his_cause = u->u.status.cause;
1757122205Sharti			stat->epref = u->u.status.epref;
1758122205Sharti			stat->epstate = u->u.status.epstate;
1759122205Sharti			stat->my_cause = 0;
1760122205Sharti			c->uni->funcs->uni_output(c->uni, c->uni->arg,
1761122205Sharti			    UNIAPI_STATUS_indication, 0, api);
1762122205Sharti		}
1763122205Sharti
1764122205Sharti		uni_msg_destroy(m);
1765122205Sharti		UNI_FREE(u);
1766122205Sharti
1767122205Sharti		return;
1768122205Sharti	}
1769122205Sharti
1770122205Sharti	uni_msg_destroy(m);
1771122205Sharti	UNI_FREE(u);
1772122205Sharti
1773122205Sharti	/*
1774122205Sharti	 * Send indication to API
1775122205Sharti	 */
1776122205Sharti	if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) != NULL) {
1777122205Sharti		conf->release.hdr.cref.cref = c->cref;
1778122205Sharti		conf->release.hdr.cref.flag = c->mine;
1779122205Sharti		conf->release.hdr.act = UNI_MSGACT_DEFAULT;
1780122205Sharti		MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER,
1781122205Sharti		    UNI_CAUSE_MSG_INCOMP);
1782122205Sharti		ADD_CAUSE_MTYPE(conf->release.cause[0], UNI_STATUS);
1783122205Sharti
1784122205Sharti		c->uni->funcs->uni_output(c->uni, c->uni->arg,
1785122205Sharti		    UNIAPI_RELEASE_confirm, 0, api);
1786122205Sharti	}
1787122205Sharti
1788122205Sharti	uni_destroy_call(c, 0);
1789122205Sharti}
1790122205Sharti
1791122205Shartistatic int
1792122205Shartistatus_enq_filter(struct sig *sig, void *arg)
1793122205Sharti{
1794122205Sharti	return (sig->type == SIG_CALL &&
1795122205Sharti	    (struct call *)arg == sig->call &&
1796122205Sharti	    sig->sig == SIGC_SEND_STATUS_ENQ);
1797122205Sharti}
1798122205Sharti
1799122205Sharti/*
1800122205Sharti * STATUS in any state except U0/U11/U12 N0/N11/N12
1801122205Sharti *
1802122205Sharti * Q.2971:Call-Control-U 32/39
1803122205Sharti * Q.2971:Call-Control-N 33/39
1804122205Sharti */
1805122205Shartistatic void
1806122205Shartiunx_status(struct call *c, struct uni_msg *m, struct uni_all *u)
1807122205Sharti{
1808122205Sharti	struct uniapi_status_indication *stat;
1809122205Sharti	struct uniapi_release_confirm *conf;
1810122205Sharti	enum call_state ns;
1811122205Sharti	struct uni_msg *api;
1812122205Sharti	struct party *p;
1813122205Sharti
1814122205Sharti	/*
1815122205Sharti	 * Analyze message
1816122205Sharti	 */
1817122205Sharti	(void)uni_decode_body(m, u, &c->uni->cx);
1818122205Sharti	MANDATE_IE(c->uni, u->u.status.callstate, UNI_IE_CALLSTATE);
1819122205Sharti	MANDATE_IE(c->uni, u->u.status.cause, UNI_IE_CAUSE);
1820122205Sharti
1821122205Sharti	ns = c->cstate;
1822122205Sharti	if (IE_ISGOOD(u->u.status.callstate))
1823122205Sharti		ns = state_compat(c, u->u.status.callstate.state);
1824122205Sharti
1825122205Sharti	p = NULL;
1826122205Sharti	if (IE_ISGOOD(u->u.status.epref)) {
1827122205Sharti		p = uni_find_party(c, &u->u.status.epref);
1828122205Sharti		MANDATE_IE(c->uni, u->u.status.epstate, UNI_IE_EPSTATE);
1829122205Sharti	}
1830122205Sharti
1831122205Sharti	switch (uni_verify(c->uni, u->u.hdr.act)) {
1832122205Sharti
1833122205Sharti	  case VFY_CLR:
1834122205Sharti		uni_vfy_collect_ies(c->uni);
1835122205Sharti		clear_callD(c);
1836122205Sharti		uni_msg_destroy(m);
1837122205Sharti		UNI_FREE(u);
1838122205Sharti	  	return;
1839122205Sharti
1840122205Sharti	  case VFY_RAIM:
1841122205Sharti	  case VFY_RAI:
1842122205Sharti	  case VFY_RAP:
1843122205Sharti	  case VFY_RAPU:
1844122205Sharti		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
1845122205Sharti		    map_callstate(ns), &u->u.notify.epref,
1846122205Sharti		    p ? p->state : UNI_EPSTATE_NULL);
1847122205Sharti		/* FALLTHRU */
1848122205Sharti	  case VFY_I:
1849122205Sharti	  case VFY_OK:
1850122205Sharti	  	break;
1851122205Sharti	}
1852122205Sharti
1853122205Sharti	if (u->u.status.callstate.state == UNI_CALLSTATE_U0) {
1854122205Sharti		/* release_complete */
1855122205Sharti		uni_msg_destroy(m);
1856122205Sharti		UNI_FREE(u);
1857122205Sharti
1858122205Sharti		if (c->type == CALL_LEAF || c->type == CALL_ROOT) {
1859122205Sharti			TAILQ_FOREACH(p, &c->parties, link)
1860122205Sharti				uni_enq_party(p, SIGP_RELEASE_COMPL,
1861122205Sharti				    0, NULL, NULL);
1862122205Sharti		}
1863122205Sharti		/*
1864122205Sharti		 * Send indication to API
1865122205Sharti		 */
1866122205Sharti		conf = ALLOC_API(struct uniapi_release_confirm, api);
1867122205Sharti		if (conf != NULL) {
1868122205Sharti			conf->release.hdr.cref.cref = c->cref;
1869122205Sharti			conf->release.hdr.cref.flag = c->mine;
1870122205Sharti			conf->release.hdr.act = UNI_MSGACT_DEFAULT;
1871122205Sharti			MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER,
1872122205Sharti			    UNI_CAUSE_MSG_INCOMP);
1873122205Sharti			ADD_CAUSE_MTYPE(conf->release.cause[0], UNI_STATUS);
1874122205Sharti
1875122205Sharti			c->uni->funcs->uni_output(c->uni, c->uni->arg,
1876122205Sharti			    UNIAPI_RELEASE_confirm, 0, api);
1877122205Sharti		}
1878122205Sharti		uni_destroy_call(c, 0);
1879122205Sharti		return;
1880122205Sharti	}
1881122205Sharti
1882122205Sharti	if (IE_ISGOOD(u->u.status.cause) &&
1883122205Sharti	    u->u.status.cause.cause == UNI_CAUSE_STATUS) {
1884122205Sharti		c->se_active = 0;
1885122205Sharti		TIMER_STOP_CALL(c, t322);
1886122205Sharti		uni_undel(c->uni, status_enq_filter, c);
1887122205Sharti	}
1888122205Sharti
1889122205Sharti	/*
1890122205Sharti	 * Inform API
1891122205Sharti	 */
1892122205Sharti	if ((stat = ALLOC_API(struct uniapi_status_indication, api)) != NULL) {
1893122205Sharti		stat->cref = u->u.hdr.cref;
1894122205Sharti		stat->my_state = map_callstate(c->cstate);
1895122205Sharti		stat->his_state = u->u.status.callstate;
1896122205Sharti		stat->his_cause = u->u.status.cause;
1897122205Sharti		stat->epref = u->u.status.epref;
1898122205Sharti		stat->epstate = u->u.status.epstate;
1899122205Sharti	}
1900122205Sharti
1901122205Sharti	if (ns == c->cstate) {
1902122205Sharti		/* compatible or recovered */
1903122205Sharti		if (p != NULL)
1904122205Sharti			uni_enq_party(p, SIGP_STATUS, 0, m, u);
1905122205Sharti		else {
1906122205Sharti			if (IE_ISGOOD(u->u.status.epref) &&
1907122205Sharti			    (!IE_ISGOOD(u->u.status.epstate) ||
1908122205Sharti			     u->u.status.epstate.state != UNI_EPSTATE_NULL))
1909122205Sharti				respond_drop_party_ack(c, &u->u.status.epref,
1910122205Sharti				    UNI_CAUSE_MSG_INCOMP);
1911122205Sharti
1912122205Sharti			uni_msg_destroy(m);
1913122205Sharti			UNI_FREE(u);
1914122205Sharti		}
1915122205Sharti		if (stat != NULL) {
1916122205Sharti			stat->my_cause = 0;
1917122205Sharti			c->uni->funcs->uni_output(c->uni, c->uni->arg,
1918122205Sharti			    UNIAPI_STATUS_indication, 0, api);
1919122205Sharti		}
1920122205Sharti
1921122205Sharti		return;
1922122205Sharti	}
1923122205Sharti
1924122205Sharti	/* incompatible */
1925122205Sharti	if (stat != NULL) {
1926122205Sharti		stat->my_cause = UNI_CAUSE_MSG_INCOMP;
1927122205Sharti		c->uni->funcs->uni_output(c->uni, c->uni->arg,
1928122205Sharti		    UNIAPI_STATUS_indication, 0, api);
1929122205Sharti	}
1930122205Sharti
1931122205Sharti	MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_MSG_INCOMP);
1932122205Sharti
1933122205Sharti	uni_msg_destroy(m);
1934122205Sharti	UNI_FREE(u);
1935122205Sharti
1936122205Sharti	clear_callD(c);
1937122205Sharti}
1938122205Sharti
1939122205Sharti/*
1940122205Sharti * Enquiry peer status
1941122205Sharti *
1942122205Sharti * Q.2971:Call-Control-U 31/39
1943122205Sharti * Q.2971:Call-Control-N 32/39
1944122205Sharti */
1945122205Shartistatic void
1946131826Shartiunx_status_enquiry_request(struct call *c, struct uni_msg *msg, uint32_t cookie)
1947122205Sharti{
1948122205Sharti	struct uniapi_status_enquiry_request *arg =
1949122205Sharti	    uni_msg_rptr(msg, struct uniapi_status_enquiry_request *);
1950122205Sharti	struct party *p;
1951122205Sharti	struct uni_all *stat;
1952122205Sharti
1953122205Sharti	if (c->se_active) {
1954122205Sharti		/* This case is not handled in the SDLs */
1955122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BUSY, cookie);
1956122205Sharti		uni_msg_destroy(msg);
1957122205Sharti		return;
1958122205Sharti	}
1959122205Sharti	if ((c->type == CALL_ROOT || c->type == CALL_LEAF) &&
1960122205Sharti	    IE_ISGOOD(arg->epref)) {
1961122205Sharti		if ((p = uni_find_partyx(c, arg->epref.epref, !arg->epref.flag))
1962122205Sharti		    == NULL) {
1963122205Sharti			uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
1964122205Sharti			uni_msg_destroy(msg);
1965122205Sharti			return;
1966122205Sharti		}
1967122205Sharti		uni_msg_destroy(msg);
1968122205Sharti		uni_enq_party(p, SIGP_STATUS_ENQUIRY_request, cookie,
1969122205Sharti		    NULL, NULL);
1970122205Sharti		return;
1971122205Sharti	}
1972122205Sharti	if ((stat = UNI_ALLOC()) == NULL) {
1973122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
1974122205Sharti		uni_msg_destroy(msg);
1975122205Sharti		return;
1976122205Sharti	}
1977122205Sharti	memset(&c->stat_epref, 0, sizeof(c->stat_epref));
1978122205Sharti	MK_MSG_ORIG(stat, UNI_STATUS_ENQ, c->cref, !c->mine);
1979122205Sharti	(void)uni_send_output(stat, c->uni);
1980122205Sharti	UNI_FREE(stat);
1981122205Sharti
1982122205Sharti	TIMER_START_CALL(c, t322, c->uni->timer322);
1983122205Sharti	c->cnt322 = 0;
1984122205Sharti	c->se_active = 1;
1985122205Sharti
1986122205Sharti	uniapi_call_error(c, UNIAPI_OK, cookie);
1987122205Sharti}
1988122205Sharti
1989122205Sharti/*
1990122205Sharti * T322 tick
1991122205Sharti *
1992122205Sharti * Q.2971:Call-Control-U 34/39
1993122205Sharti * Q.2971:Call-Control-N 35/39
1994122205Sharti */
1995122205Shartistatic void
1996122205Shartiunx_t322(struct call *c)
1997122205Sharti{
1998122205Sharti	struct uni_all *stat;
1999122205Sharti
2000122205Sharti	VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T322 tick %d",
2001122205Sharti	    c->cref, c->mine ? "mine" : "his", c->cnt322 + 1);
2002122205Sharti
2003122205Sharti	if (++c->cnt322 < c->uni->init322) {
2004122205Sharti		if ((stat = UNI_ALLOC()) != NULL) {
2005122205Sharti			MK_MSG_ORIG(stat, UNI_STATUS_ENQ, c->cref, !c->mine);
2006122205Sharti			stat->u.status_enq.epref = c->stat_epref;
2007122205Sharti			(void)uni_send_output(stat, c->uni);
2008122205Sharti			UNI_FREE(stat);
2009122205Sharti		}
2010122205Sharti		TIMER_START_CALL(c, t322, c->uni->timer322);
2011122205Sharti		return;
2012122205Sharti	}
2013122205Sharti	c->se_active = 0;
2014122205Sharti
2015122205Sharti	MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_RECOVER);
2016122205Sharti	ADD_CAUSE_TIMER(c->uni->cause, "322");
2017122205Sharti
2018122205Sharti	clear_callD(c);
2019122205Sharti}
2020122205Sharti
2021122205Sharti/*
2022122205Sharti * STATUS ENQUIRY message
2023122205Sharti *
2024122205Sharti * Q.2971:Call-Control-U 31/39
2025122205Sharti * Q.2971:Call-Control-N 32/39
2026122205Sharti */
2027122205Shartistatic void
2028122205Shartiunx_status_enq(struct call *c, struct uni_msg *m, struct uni_all *u)
2029122205Sharti{
2030122205Sharti	struct party *p = NULL;
2031122205Sharti	u_int epref, flag;
2032122205Sharti
2033122205Sharti	/*
2034122205Sharti	 * Analyze message
2035122205Sharti	 */
2036122205Sharti	(void)uni_decode_body(m, u, &c->uni->cx);
2037122205Sharti
2038122205Sharti	switch (uni_verify(c->uni, u->u.hdr.act)) {
2039122205Sharti
2040122205Sharti	  case VFY_CLR:
2041122205Sharti		uni_vfy_collect_ies(c->uni);
2042122205Sharti		clear_callD(c);
2043122205Sharti		uni_msg_destroy(m);
2044122205Sharti		UNI_FREE(u);
2045122205Sharti	  	return;
2046122205Sharti
2047122205Sharti	  case VFY_RAIM:
2048122205Sharti	  case VFY_RAI:
2049122205Sharti	  case VFY_RAP:
2050122205Sharti	  case VFY_RAPU:
2051122205Sharti	  case VFY_I:
2052122205Sharti	  case VFY_OK:
2053122205Sharti	  	break;
2054122205Sharti	}
2055122205Sharti
2056122205Sharti	uni_msg_destroy(m);
2057122205Sharti
2058122205Sharti	if ((c->type == CALL_ROOT || c->type == CALL_LEAF) &&
2059122205Sharti	    IE_ISGOOD(u->u.status_enq.epref)) {
2060122205Sharti		p = uni_find_party(c, &u->u.status_enq.epref);
2061122205Sharti
2062122205Sharti		epref = u->u.status_enq.epref.epref;
2063122205Sharti		flag = u->u.status_enq.epref.flag;
2064122205Sharti		memset(u, 0, sizeof(*u));
2065122205Sharti		MK_IE_EPREF(u->u.status.epref, epref, !flag);
2066122205Sharti
2067122205Sharti		if (p != NULL)
2068122205Sharti			MK_IE_EPSTATE(u->u.status.epstate, p->state);
2069122205Sharti		else
2070122205Sharti			MK_IE_EPSTATE(u->u.status.epstate, UNI_EPSTATE_NULL);
2071122205Sharti	} else
2072122205Sharti		memset(u, 0, sizeof(*u));
2073122205Sharti
2074122205Sharti
2075122205Sharti	MK_MSG_ORIG(u, UNI_STATUS, c->cref, !c->mine);
2076122205Sharti	MK_IE_CALLSTATE(u->u.status.callstate, map_callstate(c->cstate));
2077122205Sharti	MK_IE_CAUSE(u->u.status.cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_STATUS);
2078122205Sharti	(void)uni_send_output(u, c->uni);
2079122205Sharti	UNI_FREE(u);
2080122205Sharti}
2081122205Sharti
2082122205Sharti/**********************************************************************/
2083122205Sharti
2084122205Sharti/*
2085122205Sharti * Link-release.indication from SAAL in state U10 or N10.
2086122205Sharti *
2087122205Sharti * Q.2971:Call-Control-U 19/39
2088122205Sharti * Q.2971:Call-Control-N 20/39
2089122205Sharti */
2090122205Shartistatic void
2091122205Shartiun10_link_release_indication(struct call *c)
2092122205Sharti{
2093122205Sharti	struct party *p;
2094122205Sharti
2095122205Sharti	if (c->type == CALL_LEAF || c->type == CALL_ROOT)
2096122205Sharti		TAILQ_FOREACH(p, &c->parties, link) {
2097122205Sharti			if (p->state != UNI_EPSTATE_ACTIVE)
2098122205Sharti				uni_enq_party(p, SIGP_RELEASE_COMPL,
2099122205Sharti				    0, NULL, NULL);
2100122205Sharti		}
2101122205Sharti
2102122205Sharti	uni_enq_coord(c->uni, SIGO_LINK_ESTABLISH_request, 0, NULL);
2103122205Sharti}
2104122205Sharti
2105122205Sharti/*
2106122205Sharti * Link-release.indication from SAAL in all state except U10 and N10.
2107122205Sharti *
2108122205Sharti * Q.2971:Call-Control-U 36/39
2109122205Sharti * Q.2971:Call-Control-N 37/39
2110122205Sharti */
2111122205Shartistatic void
2112122205Shartiunx_link_release_indication(struct call *c)
2113122205Sharti{
2114122205Sharti	struct uniapi_release_confirm *conf;
2115122205Sharti	struct uni_msg *api;
2116122205Sharti	struct party *p;
2117122205Sharti
2118122205Sharti	if (c->type == CALL_LEAF || c->type == CALL_ROOT)
2119122205Sharti		TAILQ_FOREACH(p, &c->parties, link)
2120122205Sharti			uni_enq_party(p, SIGP_RELEASE_COMPL, 0, NULL, NULL);
2121122205Sharti
2122122205Sharti	if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) != NULL) {
2123122205Sharti		conf->release.hdr.cref.cref = c->cref;
2124122205Sharti		conf->release.hdr.cref.flag = c->mine;
2125122205Sharti		conf->release.hdr.act = UNI_MSGACT_DEFAULT;
2126122205Sharti		MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER,
2127122205Sharti		    UNI_CAUSE_DST_OOO);
2128122205Sharti
2129122205Sharti		c->uni->funcs->uni_output(c->uni, c->uni->arg,
2130122205Sharti		    UNIAPI_RELEASE_confirm, 0, api);
2131122205Sharti	}
2132122205Sharti
2133122205Sharti	uni_destroy_call(c, 0);
2134122205Sharti}
2135122205Sharti
2136122205Sharti/*
2137122205Sharti * Failed to establish SAAL link. Can happen only in U10 or N10.
2138122205Sharti *
2139122205Sharti * Q.2971:Call-Control-U 19/39
2140122205Sharti * Q.2971:Call-Control-N 20/39
2141122205Sharti */
2142122205Shartistatic void
2143122205Shartiun10_link_establish_error_indication(struct call *c)
2144122205Sharti{
2145122205Sharti	struct party *p;
2146122205Sharti	struct uni_msg *api;
2147122205Sharti	struct uniapi_release_confirm *conf;
2148122205Sharti
2149122205Sharti	if (c->type == CALL_LEAF || c->type == CALL_ROOT)
2150122205Sharti		TAILQ_FOREACH(p, &c->parties, link)
2151122205Sharti			uni_enq_party(p, SIGP_RELEASE_COMPL, 0, NULL, NULL);
2152122205Sharti
2153122205Sharti	if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) != NULL) {
2154122205Sharti		conf->release.hdr.cref.cref = c->cref;
2155122205Sharti		conf->release.hdr.cref.flag = c->mine;
2156122205Sharti		conf->release.hdr.act = UNI_MSGACT_DEFAULT;
2157122205Sharti		MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER,
2158122205Sharti		    UNI_CAUSE_DST_OOO);
2159122205Sharti
2160122205Sharti		c->uni->funcs->uni_output(c->uni, c->uni->arg,
2161122205Sharti		    UNIAPI_RELEASE_confirm, 0, api);
2162122205Sharti	}
2163122205Sharti
2164122205Sharti	uni_destroy_call(c, 0);
2165122205Sharti}
2166122205Sharti
2167122205Sharti/*
2168122205Sharti * Issue a STATUS ENQUIRY of we are not busy
2169122205Sharti *
2170122205Sharti * Q.2971: Call-Control-U: 34/39
2171122205Sharti * Q.2971: Call-Control-N: 34/39
2172122205Sharti */
2173122205Shartistatic void
2174122205Sharticall_se(struct call *c)
2175122205Sharti{
2176122205Sharti	struct uni_all *stat;
2177122205Sharti
2178122205Sharti	c->cnt322 = 0;
2179122205Sharti	if (c->se_active)
2180122205Sharti		return;
2181122205Sharti
2182122205Sharti	memset(&c->stat_epref, 0, sizeof(c->stat_epref));
2183122205Sharti	if ((stat = UNI_ALLOC()) != NULL) {
2184122205Sharti		MK_MSG_ORIG(stat, UNI_STATUS_ENQ, c->cref, !c->mine);
2185122205Sharti		(void)uni_send_output(stat, c->uni);
2186122205Sharti		UNI_FREE(stat);
2187122205Sharti	}
2188122205Sharti
2189122205Sharti	TIMER_START_CALL(c, t322, c->uni->timer322);
2190122205Sharti	c->se_active = 1;
2191122205Sharti}
2192122205Sharti
2193122205Sharti/*
2194122205Sharti * Link-establish.indication in U10
2195122205Sharti *
2196122205Sharti * Q.2971:Call-Control-U 19-20/39
2197122205Sharti * Q.2971:Call-Control-N 20-22/39
2198122205Sharti */
2199122205Shartistatic void
2200122205Shartiun10_link_establish_indication(struct call *c)
2201122205Sharti{
2202122205Sharti	int act = 0;
2203122205Sharti	struct party *p;
2204122205Sharti
2205122205Sharti	if (c->type == CALL_ROOT || c->type == CALL_LEAF) {
2206122205Sharti		TAILQ_FOREACH(p, &c->parties, link)
2207122205Sharti			if (p->state == UNI_EPSTATE_ACTIVE) {
2208122205Sharti				act = 1;
2209122205Sharti				uni_enq_party(p, SIGP_STATUS_ENQUIRY_request,
2210122205Sharti				    0, NULL, NULL);
2211122205Sharti			}
2212122205Sharti		if (act)
2213122205Sharti			return;
2214122205Sharti	}
2215122205Sharti	call_se(c);
2216122205Sharti}
2217122205Sharti
2218122205Sharti/*
2219122205Sharti * Link-establish.indication in NOT U10/U11/U12 N10/N11/N12
2220122205Sharti *
2221122205Sharti * Q.2971:Call-Control-U 36/39
2222122205Sharti * Q.2971:Call-Control-N 37/39
2223122205Sharti */
2224122205Shartistatic void
2225122205Shartiunx_link_establish_indication(struct call *c)
2226122205Sharti{
2227122205Sharti	call_se(c);
2228122205Sharti}
2229122205Sharti
2230122205Sharti/*
2231122205Sharti * Link-establish.confirm in U10 or N10
2232122205Sharti *
2233122205Sharti * Q.2971:Call-Control-U 19/39
2234122205Sharti * Q.2971:Call-Control-N 20/39
2235122205Sharti */
2236122205Shartistatic void
2237122205Shartiun10_link_establish_confirm(struct call *c)
2238122205Sharti{
2239122205Sharti	struct party *p;
2240122205Sharti
2241122205Sharti	if (c->type == CALL_ROOT || c->type == CALL_LEAF) {
2242122205Sharti		TAILQ_FOREACH(p, &c->parties, link)
2243122205Sharti			uni_enq_party(p, SIGP_STATUS_ENQUIRY_request,
2244122205Sharti			    0, NULL, NULL);
2245122205Sharti		return;
2246122205Sharti	}
2247122205Sharti
2248122205Sharti	call_se(c);
2249122205Sharti}
2250122205Sharti
2251122205Sharti/*
2252122205Sharti * STATUS ENQ from party
2253122205Sharti *
2254122205Sharti * Q.2971:Call-Control-U 21/39
2255122205Sharti * Q.2971:Call-Control-U 25/39
2256122205Sharti */
2257122205Shartistatic void
2258122205Shartiunx_send_party_status_enq(struct call *c, struct uni_all *u)
2259122205Sharti{
2260122205Sharti	if (c->se_active) {
2261122205Sharti		uni_delenq_sig(c->uni, SIG_CALL, c, NULL,
2262122205Sharti		    SIGC_SEND_STATUS_ENQ, 0, NULL, u);
2263122205Sharti		return;
2264122205Sharti	}
2265122205Sharti
2266122205Sharti	c->stat_epref = u->u.status_enq.epref;
2267122205Sharti	(void)uni_send_output(u, c->uni);
2268122205Sharti	UNI_FREE(u);
2269122205Sharti
2270122205Sharti	TIMER_START_CALL(c, t322, c->uni->timer322);
2271122205Sharti	c->se_active = 1;
2272122205Sharti}
2273122205Sharti
2274122205Sharti/**********************************************************************/
2275122205Sharti
2276122205Shartistatic void
2277122205Shartimake_drop_cause(struct call *c, struct uni_ie_cause *cause)
2278122205Sharti{
2279122205Sharti
2280122205Sharti	if (!IE_ISGOOD(*cause)) {
2281122205Sharti		/* 9.5.7.1 paragraph 2 */
2282122205Sharti		if (IE_ISPRESENT(*cause))
2283122205Sharti			MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER,
2284122205Sharti			    UNI_CAUSE_IE_INV);
2285122205Sharti		else
2286122205Sharti			MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER,
2287122205Sharti			    UNI_CAUSE_MANDAT);
2288122205Sharti		c->uni->cause.u.ie.len = 1;
2289122205Sharti		c->uni->cause.u.ie.ie[0] = UNI_IE_CAUSE;
2290122205Sharti		c->uni->cause.h.present |= UNI_CAUSE_IE_P;
2291122205Sharti
2292122205Sharti	} else if (!IE_ISGOOD(c->uni->cause))
2293122205Sharti		c->uni->cause = *cause;
2294122205Sharti}
2295122205Sharti
2296122205Sharti/*
2297122205Sharti * Drop-party.indication from Party-Control in any state.
2298122205Sharti *
2299122205Sharti * Q.2971:Call-Control-U 23/39
2300122205Sharti */
2301122205Shartistatic void
2302122205Shartiux_drop_party_indication(struct call *c, struct uni_msg *api)
2303122205Sharti{
2304122205Sharti	struct uniapi_drop_party_indication *drop =
2305122205Sharti	    uni_msg_rptr(api, struct uniapi_drop_party_indication *);
2306122205Sharti
2307122205Sharti	if (uni_party_act_count(c, 2) == 0) {
2308122205Sharti		if (c->cstate != CALLST_U11) {
2309122205Sharti			make_drop_cause(c, &drop->drop.cause);
2310122205Sharti			clear_callD(c);
2311122205Sharti		}
2312122205Sharti		uni_msg_destroy(api);
2313122205Sharti		return;
2314122205Sharti	}
2315122205Sharti	c->uni->funcs->uni_output(c->uni, c->uni->arg,
2316122205Sharti	    UNIAPI_DROP_PARTY_indication, 0, api);
2317122205Sharti}
2318122205Sharti
2319122205Sharti/*
2320122205Sharti * Drop-party.indication from Party-Control in any state.
2321122205Sharti *
2322122205Sharti * Q.2971:Call-Control-N 23/39
2323122205Sharti */
2324122205Shartistatic void
2325122205Shartinx_drop_party_indication(struct call *c, struct uni_msg *api)
2326122205Sharti{
2327122205Sharti	struct uniapi_drop_party_indication *drop =
2328122205Sharti	    uni_msg_rptr(api, struct uniapi_drop_party_indication *);
2329122205Sharti
2330122205Sharti	if (uni_party_act_count(c, 0) == 0) {
2331122205Sharti		if (uni_party_act_count(c, 1) == 0) {
2332122205Sharti			if (c->cstate != CALLST_U11) {
2333122205Sharti				make_drop_cause(c, &drop->drop.cause);
2334122205Sharti				clear_callD(c);
2335122205Sharti			}
2336122205Sharti			uni_msg_destroy(api);
2337122205Sharti		} else {
2338122205Sharti			c->uni->funcs->uni_output(c->uni, c->uni->arg,
2339122205Sharti			    UNIAPI_DROP_PARTY_indication, 0, api);
2340122205Sharti			set_call_state(c, CALLST_N7);
2341122205Sharti		}
2342122205Sharti	} else {
2343122205Sharti		c->uni->funcs->uni_output(c->uni, c->uni->arg,
2344122205Sharti		    UNIAPI_DROP_PARTY_indication, 0, api);
2345122205Sharti	}
2346122205Sharti}
2347122205Sharti
2348122205Sharti/*
2349122205Sharti * Drop-party-ack.indication from Party-Control in any state.
2350122205Sharti *
2351122205Sharti * Q.2971:Call-Control-U 23/39
2352122205Sharti */
2353122205Shartistatic void
2354122205Shartiux_drop_party_ack_indication(struct call *c, struct uni_msg *api)
2355122205Sharti{
2356122205Sharti	struct uniapi_drop_party_ack_indication *drop =
2357122205Sharti	    uni_msg_rptr(api, struct uniapi_drop_party_ack_indication *);
2358122205Sharti
2359122205Sharti	if (uni_party_act_count(c, 2) == 0) {
2360122205Sharti		if (c->cstate != CALLST_U11) {
2361122205Sharti			make_drop_cause(c, &drop->drop.cause);
2362122205Sharti			clear_callD(c);
2363122205Sharti		}
2364122205Sharti		uni_msg_destroy(api);
2365122205Sharti		return;
2366122205Sharti	}
2367122205Sharti	c->uni->funcs->uni_output(c->uni, c->uni->arg,
2368122205Sharti	    UNIAPI_DROP_PARTY_ACK_indication, 0, api);
2369122205Sharti}
2370122205Sharti
2371122205Sharti/*
2372122205Sharti * Drop-party-ack.indication from Party-Control in any state.
2373122205Sharti *
2374122205Sharti * Q.2971:Call-Control-N 23/39
2375122205Sharti */
2376122205Shartistatic void
2377122205Shartinx_drop_party_ack_indication(struct call *c, struct uni_msg *api)
2378122205Sharti{
2379122205Sharti	struct uniapi_drop_party_ack_indication *drop =
2380122205Sharti	    uni_msg_rptr(api, struct uniapi_drop_party_ack_indication *);
2381122205Sharti
2382122205Sharti	if (uni_party_act_count(c, 0) == 0) {
2383122205Sharti		if (uni_party_act_count(c, 1) == 0) {
2384122205Sharti			if (c->cstate != CALLST_U11) {
2385122205Sharti				make_drop_cause(c, &drop->drop.cause);
2386122205Sharti				clear_callD(c);
2387122205Sharti			}
2388122205Sharti			uni_msg_destroy(api);
2389122205Sharti		} else {
2390122205Sharti			c->uni->funcs->uni_output(c->uni, c->uni->arg,
2391122205Sharti			    UNIAPI_DROP_PARTY_ACK_indication, 0, api);
2392122205Sharti			set_call_state(c, CALLST_N7);
2393122205Sharti		}
2394122205Sharti	} else {
2395122205Sharti		c->uni->funcs->uni_output(c->uni, c->uni->arg,
2396122205Sharti		    UNIAPI_DROP_PARTY_ACK_indication, 0, api);
2397122205Sharti	}
2398122205Sharti}
2399122205Sharti
2400122205Sharti/*
2401122205Sharti * Add-party-rej.indication from Party-Control in any state.
2402122205Sharti *
2403122205Sharti * Q.2971:Call-Control-U 23/39
2404122205Sharti */
2405122205Shartistatic void
2406122205Shartiux_add_party_rej_indication(struct call *c, struct uni_msg *api)
2407122205Sharti{
2408122205Sharti	struct uniapi_add_party_rej_indication *rej =
2409122205Sharti	    uni_msg_rptr(api, struct uniapi_add_party_rej_indication *);
2410122205Sharti
2411122205Sharti	if (uni_party_act_count(c, 2) == 0) {
2412122205Sharti		if (c->cstate != CALLST_U11) {
2413122205Sharti			make_drop_cause(c, &rej->rej.cause);
2414122205Sharti			clear_callD(c);
2415122205Sharti		}
2416122205Sharti		uni_msg_destroy(api);
2417122205Sharti		return;
2418122205Sharti	}
2419122205Sharti	c->uni->funcs->uni_output(c->uni, c->uni->arg,
2420122205Sharti	    UNIAPI_ADD_PARTY_REJ_indication, 0, api);
2421122205Sharti}
2422122205Sharti
2423122205Sharti/*
2424122205Sharti * Add-party-rej.indication from Party-Control in any state.
2425122205Sharti *
2426122205Sharti * Q.2971:Call-Control-N 23/39
2427122205Sharti */
2428122205Shartistatic void
2429122205Shartinx_add_party_rej_indication(struct call *c, struct uni_msg *api)
2430122205Sharti{
2431122205Sharti	struct uniapi_add_party_rej_indication *rej =
2432122205Sharti	    uni_msg_rptr(api, struct uniapi_add_party_rej_indication *);
2433122205Sharti
2434122205Sharti	if (uni_party_act_count(c, 0) == 0) {
2435122205Sharti		if (uni_party_act_count(c, 1) == 0) {
2436122205Sharti			if (c->cstate != CALLST_U11) {
2437122205Sharti				make_drop_cause(c, &rej->rej.cause);
2438122205Sharti				clear_callD(c);
2439122205Sharti			}
2440122205Sharti			uni_msg_destroy(api);
2441122205Sharti		} else {
2442122205Sharti			c->uni->funcs->uni_output(c->uni, c->uni->arg,
2443122205Sharti			    UNIAPI_ADD_PARTY_REJ_indication, 0, api);
2444122205Sharti			set_call_state(c, CALLST_N7);
2445122205Sharti		}
2446122205Sharti	} else {
2447122205Sharti		c->uni->funcs->uni_output(c->uni, c->uni->arg,
2448122205Sharti		    UNIAPI_ADD_PARTY_REJ_indication, 0, api);
2449122205Sharti	}
2450122205Sharti}
2451122205Sharti
2452122205Sharti/*
2453122205Sharti * Add-party.request from API in U4 or U10
2454122205Sharti *
2455122205Sharti * Q.2971:Call-Control-U 9-10/39 (U4)
2456122205Sharti * Q.2971:Call-Control-U 21/39 (U10)
2457122205Sharti * Q.2971:Call-Control-N 12/39 (N7)
2458122205Sharti * Q.2971:Call-Control-N 22/39 (N10)
2459122205Sharti */
2460122205Shartistatic void
2461131826Shartiunx_add_party_request(struct call *c, struct uni_msg *msg, uint32_t cookie)
2462122205Sharti{
2463122205Sharti	struct uniapi_add_party_request *add =
2464122205Sharti	    uni_msg_rptr(msg, struct uniapi_add_party_request *);
2465122205Sharti	struct party *p;
2466122205Sharti
2467122205Sharti	if (IE_ISGOOD(add->add.epref)) {
2468122205Sharti		if (add->add.epref.flag != 0) {
2469122205Sharti			uni_msg_destroy(msg);
2470122205Sharti			uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2471122205Sharti			return;
2472122205Sharti		}
2473122205Sharti		p = uni_find_partyx(c, add->add.epref.epref, 1);
2474122205Sharti		if (p != NULL) {
2475122205Sharti			uni_msg_destroy(msg);
2476122205Sharti			uniapi_call_error(c, UNIAPI_ERROR_EPREF_INUSE, cookie);
2477122205Sharti			return;
2478122205Sharti		}
2479122205Sharti	} else if (!IE_ISPRESENT(add->add.epref)) {
2480122205Sharti		allocate_epref(c, &add->add.epref);
2481122205Sharti		if (!IE_ISPRESENT(add->add.epref)) {
2482122205Sharti			uni_msg_destroy(msg);
2483122205Sharti			uniapi_call_error(c, UNIAPI_ERROR_EPREF_INUSE, cookie);
2484122205Sharti			return;
2485122205Sharti		}
2486122205Sharti	} else {
2487122205Sharti		uni_msg_destroy(msg);
2488122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2489122205Sharti		return;
2490122205Sharti	}
2491122205Sharti
2492122205Sharti	if ((p = uni_create_partyx(c, add->add.epref.epref, 1, cookie)) == NULL) {
2493122205Sharti		uni_msg_destroy(msg);
2494122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
2495122205Sharti		return;
2496122205Sharti	}
2497122205Sharti	uni_enq_party(p, SIGP_ADD_PARTY_request, cookie, msg, NULL);
2498122205Sharti}
2499122205Sharti
2500122205Sharti/*
2501122205Sharti * Add-party-ack.request from API in U10/N10
2502122205Sharti *
2503122205Sharti * Q.2971:Call-Control-U 21/39
2504122205Sharti * Q.2971:Call-Control-N 22/39
2505122205Sharti */
2506122205Shartistatic void
2507131826Shartiun10_add_party_ack_request(struct call *c, struct uni_msg *msg, uint32_t cookie)
2508122205Sharti{
2509122205Sharti	struct uniapi_add_party_ack_request *ack =
2510122205Sharti	    uni_msg_rptr(msg, struct uniapi_add_party_ack_request *);
2511122205Sharti	struct party *p;
2512122205Sharti
2513122205Sharti	if (!IE_ISGOOD(ack->ack.epref)) {
2514122205Sharti		uni_msg_destroy(msg);
2515122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2516122205Sharti		return;
2517122205Sharti	}
2518122205Sharti	if (ack->ack.epref.flag != 1) {
2519122205Sharti		uni_msg_destroy(msg);
2520122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2521122205Sharti		return;
2522122205Sharti	}
2523122205Sharti	if ((p = uni_find_partyx(c, ack->ack.epref.epref, 0)) == NULL) {
2524122205Sharti		uni_msg_destroy(msg);
2525122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
2526122205Sharti		return;
2527122205Sharti	}
2528122205Sharti
2529122205Sharti	uni_enq_party(p, SIGP_ADD_PARTY_ACK_request, cookie, msg, NULL);
2530122205Sharti}
2531122205Sharti
2532122205Sharti/*
2533122205Sharti * Party-alerting.request from API in U7/U8/U10
2534122205Sharti *
2535122205Sharti * Q.2971:Call-Control-U 14/39 U7
2536122205Sharti * Q.2971:Call-Control-U 15/39 U8
2537122205Sharti * Q.2971:Call-Control-U 21/39 U10
2538122205Sharti * Q.2971:Call-Control-N 8/39  N4
2539122205Sharti * Q.2971:Call-Control-N 22/39 N10
2540122205Sharti */
2541122205Shartistatic void
2542131826Shartiunx_party_alerting_request(struct call *c, struct uni_msg *msg, uint32_t cookie)
2543122205Sharti{
2544122205Sharti	struct uniapi_party_alerting_request *alert =
2545122205Sharti	    uni_msg_rptr(msg, struct uniapi_party_alerting_request *);
2546122205Sharti	struct party *p;
2547122205Sharti
2548122205Sharti	if (!IE_ISGOOD(alert->alert.epref)) {
2549122205Sharti		uni_msg_destroy(msg);
2550122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2551122205Sharti		return;
2552122205Sharti	}
2553122205Sharti	if (alert->alert.epref.flag != 1) {
2554122205Sharti		uni_msg_destroy(msg);
2555122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2556122205Sharti		return;
2557122205Sharti	}
2558122205Sharti	if ((p = uni_find_partyx(c, alert->alert.epref.epref, 0)) == NULL) {
2559122205Sharti		uni_msg_destroy(msg);
2560122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
2561122205Sharti		return;
2562122205Sharti	}
2563122205Sharti
2564122205Sharti	uni_enq_party(p, SIGP_PARTY_ALERTING_request, cookie, msg, NULL);
2565122205Sharti}
2566122205Sharti
2567122205Sharti/*
2568122205Sharti * Add-party-rej.request from API in U7/U8/U10/N4/N10
2569122205Sharti *
2570122205Sharti * Q.2971:Call-Control-U 14/39 U7
2571122205Sharti * Q.2971:Call-Control-U 15/39 U8
2572122205Sharti * Q.2971:Call-Control-U 21/39 U10
2573122205Sharti * Q.2971:Call-Control-N 8/39  N4
2574122205Sharti * Q.2971:Call-Control-N 22/39 N10
2575122205Sharti */
2576122205Shartistatic void
2577131826Shartiunx_add_party_rej_request(struct call *c, struct uni_msg *msg, uint32_t cookie)
2578122205Sharti{
2579122205Sharti	struct uniapi_add_party_rej_request *rej =
2580122205Sharti	    uni_msg_rptr(msg, struct uniapi_add_party_rej_request *);
2581122205Sharti	struct party *p;
2582122205Sharti
2583122205Sharti	if (!IE_ISGOOD(rej->rej.epref)) {
2584122205Sharti		uni_msg_destroy(msg);
2585122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2586122205Sharti		return;
2587122205Sharti	}
2588122205Sharti	if (rej->rej.epref.flag != 1) {
2589122205Sharti		uni_msg_destroy(msg);
2590122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2591122205Sharti		return;
2592122205Sharti	}
2593122205Sharti	if ((p = uni_find_partyx(c, rej->rej.epref.epref, 0)) == NULL) {
2594122205Sharti		uni_msg_destroy(msg);
2595122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
2596122205Sharti		return;
2597122205Sharti	}
2598122205Sharti
2599122205Sharti	uni_enq_party(p, SIGP_ADD_PARTY_REJ_request, cookie, msg, NULL);
2600122205Sharti}
2601122205Sharti
2602122205Sharti/*
2603122205Sharti * Drop-party.request from API in U1-U10
2604122205Sharti *
2605122205Sharti * Q.2971:Call-Control-U 21/39 U10
2606122205Sharti * Q.2971:Call-Control-U 26/39 U1-U9
2607122205Sharti * Q.2971:Call-Control-N 22/39 N10
2608122205Sharti * Q.2971:Call-Control-N 27/39 N1-N9
2609122205Sharti */
2610122205Shartistatic void
2611131826Shartiunx_drop_party_request(struct call *c, struct uni_msg *msg, uint32_t cookie)
2612122205Sharti{
2613122205Sharti	struct uniapi_drop_party_request *drop =
2614122205Sharti	    uni_msg_rptr(msg, struct uniapi_drop_party_request *);
2615122205Sharti	struct party *p;
2616122205Sharti
2617122205Sharti	if (!IE_ISGOOD(drop->drop.epref)) {
2618122205Sharti		uni_msg_destroy(msg);
2619122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2620122205Sharti		return;
2621122205Sharti	}
2622122205Sharti	if ((p = uni_find_partyx(c, drop->drop.epref.epref, !drop->drop.epref.flag)) == NULL) {
2623122205Sharti		uni_msg_destroy(msg);
2624122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
2625122205Sharti		return;
2626122205Sharti	}
2627122205Sharti
2628122205Sharti	uni_enq_party(p, SIGP_DROP_PARTY_request, cookie, msg, NULL);
2629122205Sharti}
2630122205Sharti
2631122205Sharti/*
2632122205Sharti * Drop-party-ack.request from API in U1-U10
2633122205Sharti *
2634122205Sharti * Q.2971:Call-Control-U 21/39 U10
2635122205Sharti * Q.2971:Call-Control-U 26/39 U1-U9
2636122205Sharti * Q.2971:Call-Control-N 22/39 N10
2637122205Sharti * Q.2971:Call-Control-N 27/39 N1-N9
2638122205Sharti */
2639122205Shartistatic void
2640122205Shartiunx_drop_party_ack_request(struct call *c, struct uni_msg *msg,
2641131826Sharti    uint32_t cookie)
2642122205Sharti{
2643122205Sharti	struct uniapi_drop_party_ack_request *ack =
2644122205Sharti	    uni_msg_rptr(msg, struct uniapi_drop_party_ack_request *);
2645122205Sharti	struct party *p;
2646122205Sharti
2647122205Sharti	if (!IE_ISGOOD(ack->ack.epref)) {
2648122205Sharti		uni_msg_destroy(msg);
2649122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2650122205Sharti		return;
2651122205Sharti	}
2652122205Sharti	if ((p = uni_find_partyx(c, ack->ack.epref.epref, !ack->ack.epref.flag)) == NULL) {
2653122205Sharti		uni_msg_destroy(msg);
2654122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
2655122205Sharti		return;
2656122205Sharti	}
2657122205Sharti
2658122205Sharti	uni_enq_party(p, SIGP_DROP_PARTY_ACK_request, cookie, msg, NULL);
2659122205Sharti}
2660122205Sharti
2661122205Sharti/*
2662122205Sharti * ADD PARTY in U7/U8/U10
2663122205Sharti *
2664122205Sharti * Q.2971:Call-Control-U 14/39  U7
2665122205Sharti * Q.2971:Call-Control-U 15/39  U8
2666122205Sharti * Q.2971:Call-Control-U 21/39  U10
2667122205Sharti * Q.2971:Call-Control-N 8/39   N4
2668122205Sharti * Q.2971:Call-Control-N 21/39  N10
2669122205Sharti *
2670122205Sharti * Body already decoded
2671131826Sharti * XXX check EPREF flag
2672122205Sharti */
2673122205Shartistatic void
2674122205Shartiunx_add_party(struct call *c, struct uni_msg *m, struct uni_all *u,
2675122205Sharti    int legal)
2676122205Sharti{
2677122205Sharti	struct uni_all *resp;
2678122205Sharti	struct uni_ierr *e1;
2679122205Sharti	struct party *p = NULL;
2680122205Sharti	enum verify vfy;
2681122205Sharti
2682122205Sharti	uni_mandate_epref(c->uni, &u->u.add_party.epref);
2683122205Sharti	MANDATE_IE(c->uni, u->u.add_party.called, UNI_IE_CALLED);
2684122205Sharti
2685122205Sharti	/*
2686122205Sharti	 * Do part of the verify handish: according to 9.5.7.2 we must send
2687122205Sharti	 * an ADD_PARTY_REJ if mandatory IEs are bad or missing instead of
2688122205Sharti	 * clearing the call. But we must send a STATUS, if it is the EPREF!
2689122205Sharti	 */
2690122205Sharti	if (IE_ISGOOD(u->u.add_party.epref)) {
2691122205Sharti		c->uni->cause.u.ie.len = 0;
2692122205Sharti		FOREACH_ERR(e1, c->uni) {
2693122205Sharti			if (e1->err == UNI_IERR_MIS) {
2694122205Sharti				MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER,
2695122205Sharti				    UNI_CAUSE_MANDAT);
2696122205Sharti				goto rej;
2697122205Sharti			}
2698122205Sharti		}
2699122205Sharti		FOREACH_ERR(e1, c->uni) {
2700122205Sharti			if (e1->man && e1->ie != UNI_IE_EPREF &&
2701122205Sharti			    e1->act == UNI_IEACT_DEFAULT) {
2702122205Sharti				MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER,
2703122205Sharti				    UNI_CAUSE_IE_INV);
2704122205Sharti  rej:
2705122205Sharti				uni_vfy_collect_ies(c->uni);
2706122205Sharti				if ((resp = UNI_ALLOC()) != NULL) {
2707122205Sharti					MK_MSG_RESP(resp, UNI_ADD_PARTY_REJ,
2708122205Sharti					   &u->u.hdr.cref);
2709122205Sharti					MK_IE_EPREF(resp->u.add_party_rej.epref,
2710122205Sharti					    u->u.add_party.epref.epref,
2711122205Sharti					    !u->u.add_party.epref.flag);
2712122205Sharti					resp->u.add_party_rej.cause =
2713122205Sharti					    c->uni->cause;
2714122205Sharti
2715122205Sharti					unx_send_add_party_rej(c, resp);
2716122205Sharti				}
2717122205Sharti				goto ignore;
2718122205Sharti			}
2719122205Sharti		}
2720122205Sharti		p = uni_find_partyx(c, u->u.add_party.epref.epref,
2721122205Sharti		    u->u.add_party.epref.flag);
2722122205Sharti	}
2723122205Sharti
2724122205Sharti	vfy = uni_verify(c->uni, u->u.hdr.act);
2725122205Sharti
2726122205Sharti	switch (vfy) {
2727122205Sharti
2728122205Sharti	  case VFY_CLR:
2729122205Sharti		uni_vfy_collect_ies(c->uni);
2730122205Sharti		clear_callD(c);
2731122205Sharti		goto ignore;
2732122205Sharti
2733122205Sharti	  case VFY_RAIM:
2734122205Sharti	  case VFY_RAI:
2735122205Sharti		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
2736122205Sharti		    map_callstate(c->cstate), &u->u.add_party.epref,
2737122205Sharti		    p ? p->state : UNI_EPSTATE_NULL);
2738122205Sharti		/* FALLTHRU */
2739122205Sharti	  case VFY_I:
2740122205Sharti		goto ignore;
2741122205Sharti
2742122205Sharti	  case VFY_RAP:
2743122205Sharti	  case VFY_RAPU:
2744122205Sharti		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
2745122205Sharti		    map_callstate(c->cstate), &u->u.add_party.epref,
2746122205Sharti		    UNI_EPSTATE_ADD_RCVD);
2747122205Sharti	  case VFY_OK:
2748122205Sharti		/* FALLTHRU */
2749122205Sharti		break;
2750122205Sharti	}
2751122205Sharti	if (!legal) {
2752122205Sharti		uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
2753122205Sharti		    &u->u.add_party.epref, -1);
2754122205Sharti		return;
2755122205Sharti	}
2756131826Sharti
2757131826Sharti	if (IE_ISGOOD(u->u.add_party.epref) && p == NULL &&
2758131826Sharti	    u->u.add_party.epref.flag) {
2759131826Sharti		IE_SETERROR(u->u.add_party.epref);
2760213789Srpaulo		(void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF,
2761131826Sharti		    u->u.add_party.epref.h.act, UNI_IERR_BAD);
2762131826Sharti	}
2763131826Sharti
2764122205Sharti	if (!IE_ISGOOD(u->u.add_party.epref)) {
2765122205Sharti		/* 9.5.3.2.2 */
2766122205Sharti		if (vfy == VFY_OK) {
2767122205Sharti			MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER,
2768122205Sharti			    UNI_CAUSE_IE_INV);
2769122205Sharti
2770122205Sharti			uni_respond_status_verify(c->uni, &u->u.hdr.cref,
2771122205Sharti			    map_callstate(c->cstate), NULL, 0);
2772122205Sharti		}
2773122205Sharti		goto ignore;
2774122205Sharti	}
2775122205Sharti
2776122205Sharti
2777122205Sharti	if (p == NULL && (p = uni_create_party(c, &u->u.add_party.epref))
2778122205Sharti	    == NULL)
2779122205Sharti		goto ignore;
2780122205Sharti
2781122205Sharti	uni_enq_party(p, SIGP_ADD_PARTY, 0, m, u);
2782122205Sharti	return;
2783122205Sharti
2784122205Sharti  ignore:
2785122205Sharti	uni_msg_destroy(m);
2786122205Sharti	UNI_FREE(u);
2787122205Sharti}
2788122205Sharti
2789122205Sharti/*
2790122205Sharti * ADD PARTY ACKNOWLEDGE
2791122205Sharti *
2792122205Sharti * Q.2971:Call-Control-U 21/39 U10
2793122205Sharti * Q.2971:Call-Control-N 15/39 N8
2794122205Sharti * Q.2971:Call-Control-N 22/39 N10
2795122205Sharti */
2796122205Shartistatic void
2797122205Shartiun10n8_add_party_ack(struct call *c, struct uni_msg *m, struct uni_all *u,
2798122205Sharti    int legal)
2799122205Sharti{
2800122205Sharti	struct party *p = NULL;
2801122205Sharti
2802122205Sharti	if (IE_ISGOOD(u->u.add_party_ack.epref)) {
2803122205Sharti		if (u->u.add_party_ack.epref.flag == 0) {
2804122205Sharti			IE_SETERROR(u->u.add_party_ack.epref);
2805213789Srpaulo			(void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF,
2806122205Sharti			    u->u.add_party_ack.epref.h.act, UNI_IERR_BAD);
2807122205Sharti		} else {
2808122205Sharti	    		p = uni_find_partyx(c, u->u.add_party_ack.epref.epref, 1);
2809122205Sharti			if (p == NULL) {
2810122205Sharti				respond_drop_party_ack(c,
2811122205Sharti				    &u->u.add_party_ack.epref,
2812122205Sharti				    UNI_CAUSE_ENDP_INV);
2813122205Sharti				goto ignore;
2814122205Sharti			}
2815122205Sharti		}
2816122205Sharti	}
2817122205Sharti	uni_mandate_epref(c->uni, &u->u.add_party_ack.epref);
2818122205Sharti
2819122205Sharti	switch (uni_verify(c->uni, u->u.hdr.act)) {
2820122205Sharti
2821122205Sharti	  case VFY_CLR:
2822122205Sharti		uni_vfy_collect_ies(c->uni);
2823122205Sharti		clear_callD(c);
2824122205Sharti		goto ignore;
2825122205Sharti
2826122205Sharti	  case VFY_RAIM:
2827122205Sharti	  case VFY_RAI:
2828122205Sharti	  report:
2829122205Sharti		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
2830122205Sharti		    map_callstate(c->cstate), &u->u.add_party_ack.epref,
2831122205Sharti		    p ? p->state : UNI_EPSTATE_NULL);
2832122205Sharti	  case VFY_I:
2833122205Sharti		goto ignore;
2834122205Sharti
2835122205Sharti	  case VFY_RAP:
2836122205Sharti	  case VFY_RAPU:
2837122205Sharti		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
2838122205Sharti		    map_callstate(c->cstate), &u->u.add_party_ack.epref,
2839122205Sharti		    p ? UNI_EPSTATE_ACTIVE : UNI_EPSTATE_NULL);
2840122205Sharti		if (!IE_ISGOOD(u->u.party_alerting.epref))
2841122205Sharti			/* See below */
2842122205Sharti			goto ignore;
2843122205Sharti		break;
2844122205Sharti	  case VFY_OK:
2845122205Sharti		if (!IE_ISGOOD(u->u.party_alerting.epref))
2846122205Sharti			/* this happens when the EPREF has bad format.
2847122205Sharti			 * The rules require us the message to be ignored
2848122205Sharti			 * (9.5.3.2.2e) and to report status.
2849122205Sharti			 */
2850122205Sharti			goto report;
2851122205Sharti		break;
2852122205Sharti	}
2853122205Sharti	if (legal) {
2854122205Sharti		/* p is != NULL here */
2855122205Sharti		uni_enq_party(p, SIGP_ADD_PARTY_ACK, 0, m, u);
2856122205Sharti		return;
2857122205Sharti	}
2858122205Sharti	if (p == NULL)
2859122205Sharti		/* Q.2971 9.5.3.2.3a) */
2860122205Sharti		respond_drop_party_ack(c, &u->u.add_party_ack.epref,
2861122205Sharti		    UNI_CAUSE_ENDP_INV);
2862122205Sharti	else
2863122205Sharti		uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
2864122205Sharti		    &u->u.add_party_ack.epref, p->state);
2865122205Sharti
2866122205Sharti  ignore:
2867122205Sharti	uni_msg_destroy(m);
2868122205Sharti	UNI_FREE(u);
2869122205Sharti}
2870122205Sharti
2871122205Sharti/*
2872122205Sharti * Make the EPREF action default
2873122205Sharti */
2874122205Shartistatic void
2875122205Shartidefault_act_epref(struct uni *uni, struct uni_ie_epref *epref)
2876122205Sharti{
2877122205Sharti	struct uni_ierr *e;
2878122205Sharti
2879122205Sharti	FOREACH_ERR(e, uni)
2880122205Sharti		if (e->ie == UNI_IE_EPREF) {
2881122205Sharti			e->act = UNI_IEACT_DEFAULT;
2882122205Sharti			break;
2883122205Sharti		}
2884122205Sharti	epref->h.act = UNI_IEACT_DEFAULT;
2885122205Sharti}
2886122205Sharti
2887122205Sharti/*
2888122205Sharti * PARTY ALERTING message
2889122205Sharti *
2890122205Sharti * Q.2971:Call-Control-U 9/39   U4
2891122205Sharti * Q.2971:Call-Control-U 21/39  U10
2892122205Sharti * Q.2971:Call-Control-N 12/39  N7
2893122205Sharti * Q.2971:Call-Control-N 15/39  N8
2894122205Sharti * Q.2971:Call-Control-N 22/39  N10
2895122205Sharti */
2896122205Shartistatic void
2897122205Shartiunx_party_alerting(struct call *c, struct uni_msg *m, struct uni_all *u,
2898122205Sharti    int legal)
2899122205Sharti{
2900122205Sharti	struct party *p = NULL;
2901122205Sharti
2902122205Sharti	if (IE_ISGOOD(u->u.party_alerting.epref)) {
2903122205Sharti		if (u->u.party_alerting.epref.flag == 0) {
2904122205Sharti			IE_SETERROR(u->u.party_alerting.epref);
2905213789Srpaulo			(void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF,
2906122205Sharti			    u->u.party_alerting.epref.h.act, UNI_IERR_BAD);
2907122205Sharti		} else {
2908122205Sharti	    		p = uni_find_partyx(c, u->u.party_alerting.epref.epref, 1);
2909122205Sharti			if (p == NULL) {
2910122205Sharti				respond_drop_party_ack(c,
2911122205Sharti				    &u->u.party_alerting.epref,
2912122205Sharti				    UNI_CAUSE_ENDP_INV);
2913122205Sharti				goto ignore;
2914122205Sharti			}
2915122205Sharti		}
2916122205Sharti	}
2917122205Sharti	uni_mandate_epref(c->uni, &u->u.party_alerting.epref);
2918122205Sharti
2919122205Sharti	switch (uni_verify(c->uni, u->u.hdr.act)) {
2920122205Sharti
2921122205Sharti	  case VFY_CLR:
2922122205Sharti		uni_vfy_collect_ies(c->uni);
2923122205Sharti		clear_callD(c);
2924122205Sharti		goto ignore;
2925122205Sharti
2926122205Sharti	  case VFY_RAIM:
2927122205Sharti	  case VFY_RAI:
2928122205Sharti	  report:
2929122205Sharti		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
2930122205Sharti		    map_callstate(c->cstate), &u->u.party_alerting.epref,
2931122205Sharti		    p ? p->state : UNI_EPSTATE_NULL);
2932122205Sharti	  case VFY_I:
2933122205Sharti		goto ignore;
2934122205Sharti
2935122205Sharti	  case VFY_RAP:
2936122205Sharti	  case VFY_RAPU:
2937122205Sharti		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
2938122205Sharti		    map_callstate(c->cstate), &u->u.party_alerting.epref,
2939122205Sharti		    p ? UNI_EPSTATE_ALERT_RCVD : UNI_EPSTATE_NULL);
2940122205Sharti		if (!IE_ISGOOD(u->u.party_alerting.epref))
2941122205Sharti			/* See below */
2942122205Sharti			goto ignore;
2943122205Sharti		break;
2944122205Sharti
2945122205Sharti	  case VFY_OK:
2946122205Sharti		if (!IE_ISGOOD(u->u.party_alerting.epref))
2947122205Sharti			/* The rules require us the message to be ignored
2948122205Sharti			 * (9.5.3.2.2e) and to report status.
2949122205Sharti			 */
2950122205Sharti			goto report;
2951122205Sharti		break;
2952122205Sharti	}
2953122205Sharti	if (legal) {
2954122205Sharti		/* p is != NULL here */
2955122205Sharti		uni_enq_party(p, SIGP_PARTY_ALERTING, 0, m, u);
2956122205Sharti		return;
2957122205Sharti	}
2958122205Sharti	if (p == NULL)
2959122205Sharti		/* Q.2971 9.5.3.2.3a) */
2960122205Sharti		respond_drop_party_ack(c, &u->u.party_alerting.epref,
2961122205Sharti		    UNI_CAUSE_ENDP_INV);
2962122205Sharti	else
2963122205Sharti		uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
2964122205Sharti		    &u->u.party_alerting.epref, p->state);
2965122205Sharti
2966122205Sharti  ignore:
2967122205Sharti	uni_msg_destroy(m);
2968122205Sharti	UNI_FREE(u);
2969122205Sharti}
2970122205Sharti
2971122205Sharti/*
2972122205Sharti * Handle a bad/missing cause in a DROP_PARTY_ACK or ADD_PARTY_REJ
2973122205Sharti *
2974122205Sharti * If the IE is missing or bad and the action is defaulted handle as
2975122205Sharti * cause #1 according to 9.5.7.1/2.
2976122205Sharti * Otherwise keep the IE.
2977122205Sharti */
2978122205Shartistatic void
2979122205Shartihandle_bad_drop_cause(struct call *c, struct uni_ie_cause *cause, int mkcause)
2980122205Sharti{
2981122205Sharti
2982122205Sharti	if (IE_ISGOOD(*cause))
2983122205Sharti		return;
2984122205Sharti
2985122205Sharti	if (!IE_ISPRESENT(*cause)) {
2986122205Sharti		/* 9.5.7.1 */
2987122205Sharti		/* cannot make cause here because we need the 96 error */
2988122205Sharti		uni_vfy_remove_cause(c->uni);
2989122205Sharti		return;
2990122205Sharti	}
2991122205Sharti	if (cause->h.act != UNI_IEACT_DEFAULT)
2992122205Sharti		return;
2993122205Sharti
2994122205Sharti	/* 9.5.7.2 */
2995122205Sharti	uni_vfy_remove_cause(c->uni);
2996122205Sharti	if (mkcause)
2997122205Sharti		MK_IE_CAUSE(*cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_UNSPEC);
2998122205Sharti}
2999122205Sharti
3000122205Sharti/*
3001122205Sharti * ADD PARTY REJ from party control
3002122205Sharti * Q.2971:Call-Control-U 21/39
3003122205Sharti * Q.2971:Call-Control-U 24/39
3004122205Sharti */
3005122205Shartistatic void
3006122205Shartiunx_send_add_party_rej(struct call *c, struct uni_all *u)
3007122205Sharti{
3008122205Sharti
3009122205Sharti	if (uni_party_act_count(c, 2) == 0) {
3010122205Sharti		if (c->cstate != CALLST_U11 && c->cstate != CALLST_N12) {
3011122205Sharti			c->uni->cause = u->u.add_party_rej.cause;
3012122205Sharti			clear_callD(c);
3013122205Sharti		}
3014122205Sharti	} else
3015122205Sharti		(void)uni_send_output(u, c->uni);
3016122205Sharti	UNI_FREE(u);
3017122205Sharti}
3018122205Sharti
3019122205Sharti/*
3020122205Sharti * ADD_PARTY_REJECT in U4/U10
3021122205Sharti *
3022122205Sharti * Q.2971:Call-Control-U 9/39 U4
3023122205Sharti * Q.2971:Call-Control-U 21/39 U10
3024122205Sharti * Q.2971:Call-Control-N 12/39 N7
3025122205Sharti * Q.2971:Call-Control-N 15/39 N8
3026122205Sharti * Q.2971:Call-Control-N 22/39 N10
3027122205Sharti */
3028122205Shartistatic void
3029122205Shartiunx_add_party_rej(struct call *c, struct uni_msg *m, struct uni_all *u,
3030122205Sharti    int legal)
3031122205Sharti{
3032122205Sharti	struct uni_add_party_rej *ar = &u->u.add_party_rej;
3033122205Sharti	struct party *p;
3034122205Sharti
3035122205Sharti	if (IE_ISGOOD(ar->epref)) {
3036122205Sharti		p = uni_find_partyx(c, ar->epref.epref, ar->epref.flag);
3037122205Sharti		if (p == NULL)
3038122205Sharti			goto ignore;
3039122205Sharti
3040122205Sharti		if (legal) {
3041122205Sharti			handle_bad_drop_cause(c, &ar->cause, 0);
3042122205Sharti			uni_vfy_remove_unknown(c->uni);
3043122205Sharti			switch (uni_verify(c->uni, u->u.hdr.act)) {
3044122205Sharti
3045122205Sharti			  case VFY_CLR:
3046122205Sharti				goto clear;
3047122205Sharti
3048122205Sharti			  case VFY_RAIM:
3049122205Sharti			  case VFY_RAI:
3050122205Sharti				uni_respond_status_verify(c->uni,
3051122205Sharti				    &u->u.hdr.cref, map_callstate(c->cstate),
3052122205Sharti				    &ar->epref, p->state);
3053122205Sharti			  case VFY_I:
3054122205Sharti				goto ignore;
3055122205Sharti
3056122205Sharti			  case VFY_RAPU:
3057122205Sharti				uni_vfy_collect_ies(c->uni);
3058122205Sharti				break;
3059122205Sharti
3060122205Sharti			  case VFY_RAP:
3061122205Sharti				uni_respond_status_verify(c->uni,
3062122205Sharti				    &u->u.hdr.cref, map_callstate(c->cstate),
3063122205Sharti				    &ar->epref, p->state);
3064122205Sharti			  case VFY_OK:
3065122205Sharti				break;
3066122205Sharti			}
3067122205Sharti			uni_enq_party(p, SIGP_ADD_PARTY_REJ, 0, m, u);
3068122205Sharti			return;
3069122205Sharti		}
3070122205Sharti		uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3071122205Sharti		    &ar->epref, -1);
3072122205Sharti		return;
3073122205Sharti	}
3074122205Sharti
3075122205Sharti	/* Q.2971: 9.5.3.2.1 last paragraph
3076122205Sharti	 *         9.5.3.2.2 second to last paragraph
3077122205Sharti	 * Make the action indicator default.
3078122205Sharti	 */
3079122205Sharti	default_act_epref(c->uni, &ar->epref);
3080122205Sharti	if (!IE_ISPRESENT(ar->epref))
3081122205Sharti		uni_mandate_ie(c->uni, UNI_IE_EPREF);
3082122205Sharti	(void)uni_verify(c->uni, u->u.hdr.act);
3083122205Sharti
3084122205Sharti  clear:
3085122205Sharti	uni_vfy_collect_ies(c->uni);
3086122205Sharti	clear_callD(c);
3087122205Sharti
3088122205Sharti  ignore:
3089122205Sharti	uni_msg_destroy(m);
3090122205Sharti	UNI_FREE(u);
3091122205Sharti}
3092122205Sharti
3093122205Sharti/*
3094122205Sharti * DROP_PARTY
3095122205Sharti *
3096122205Sharti * Q.2971:Call-Control-U 26/39 Ux
3097122205Sharti * Q.2971:Call-Control-U 21/39 U10
3098122205Sharti * Q.2971:Call-Control-N 27/39 Nx
3099122205Sharti * Q.2971:Call-Control-N 22/39 N10
3100122205Sharti */
3101122205Shartistatic void
3102122205Shartiunx_drop_party(struct call *c, struct uni_msg *m, struct uni_all *u, int legal)
3103122205Sharti{
3104122205Sharti	struct uni_drop_party *dp = &u->u.drop_party;
3105122205Sharti	struct party *p;
3106122205Sharti	struct uni_ierr *e;
3107122205Sharti
3108122205Sharti	if (IE_ISGOOD(dp->epref)) {
3109122205Sharti		p = uni_find_partyx(c, dp->epref.epref, dp->epref.flag);
3110122205Sharti		if (p == NULL) {
3111122205Sharti			respond_drop_party_ack(c, &dp->epref,
3112122205Sharti			    UNI_CAUSE_ENDP_INV);
3113122205Sharti			goto ignore;
3114122205Sharti		}
3115122205Sharti		handle_bad_drop_cause(c, &dp->cause, 0);
3116122205Sharti		uni_vfy_remove_unknown(c->uni);
3117122205Sharti		switch (uni_verify(c->uni, u->u.hdr.act)) {
3118122205Sharti
3119122205Sharti		  case VFY_CLR:
3120122205Sharti			goto clear;
3121122205Sharti
3122122205Sharti		  case VFY_RAIM:
3123122205Sharti		  case VFY_RAI:
3124122205Sharti			uni_respond_status_verify(c->uni, &u->u.hdr.cref,
3125122205Sharti			    map_callstate(c->cstate),
3126122205Sharti			    &u->u.drop_party.epref, p->state);
3127122205Sharti		  case VFY_I:
3128122205Sharti			goto ignore;
3129122205Sharti
3130122205Sharti		  case VFY_RAPU:
3131122205Sharti			uni_vfy_collect_ies(c->uni);
3132122205Sharti			break;
3133122205Sharti
3134122205Sharti		  case VFY_RAP:
3135122205Sharti			uni_respond_status_verify(c->uni, &u->u.hdr.cref,
3136122205Sharti			    map_callstate(c->cstate),
3137122205Sharti			    &dp->epref, UNI_EPSTATE_DROP_RCVD);
3138122205Sharti		  case VFY_OK:
3139122205Sharti			break;
3140122205Sharti		}
3141122205Sharti		if (legal) {
3142122205Sharti			uni_enq_party(p, SIGP_DROP_PARTY, 0, m, u);
3143122205Sharti			return;
3144122205Sharti		}
3145122205Sharti		uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, &dp->epref, -1);
3146122205Sharti		goto ignore;
3147122205Sharti	}
3148122205Sharti
3149122205Sharti	/* Q.2971: 9.5.3.2.1 last paragraph
3150122205Sharti	 *         9.5.3.2.2 second to last paragraph
3151122205Sharti	 * Make the action indicator default.
3152122205Sharti	 */
3153122205Sharti	FOREACH_ERR(e, c->uni)
3154122205Sharti		if (e->ie == UNI_IE_EPREF) {
3155122205Sharti			e->act = UNI_IEACT_DEFAULT;
3156122205Sharti			break;
3157122205Sharti		}
3158122205Sharti	dp->epref.h.act = UNI_IEACT_DEFAULT;
3159122205Sharti
3160122205Sharti	if (!IE_ISPRESENT(dp->epref))
3161122205Sharti		uni_mandate_ie(c->uni, UNI_IE_EPREF);
3162122205Sharti	(void)uni_verify(c->uni, u->u.hdr.act);
3163122205Sharti
3164122205Sharti  clear:
3165122205Sharti	uni_vfy_collect_ies(c->uni);
3166122205Sharti	clear_callD(c);
3167122205Sharti	uni_msg_destroy(m);
3168122205Sharti	UNI_FREE(u);
3169122205Sharti	return;
3170122205Sharti
3171122205Sharti  ignore:
3172122205Sharti	uni_msg_destroy(m);
3173122205Sharti	UNI_FREE(u);
3174122205Sharti}
3175122205Sharti
3176122205Sharti/*
3177122205Sharti * DROP_PARTY_ACK
3178122205Sharti *
3179122205Sharti * Q.2971:Call-Control-U 26/39 Ux
3180122205Sharti * Q.2971:Call-Control-U 21/39 U10
3181122205Sharti * Q.2971:Call-Control-N 27/39 Nx
3182122205Sharti * Q.2971:Call-Control-N 22/39 N10
3183122205Sharti */
3184122205Shartistatic void
3185122205Shartiunx_drop_party_ack(struct call *c, struct uni_msg *m, struct uni_all *u,
3186122205Sharti    int legal)
3187122205Sharti{
3188122205Sharti	struct party *p;
3189122205Sharti	struct uni_drop_party_ack *ack = &u->u.drop_party_ack;
3190122205Sharti
3191122205Sharti	if (IE_ISGOOD(u->u.drop_party_ack.epref)) {
3192122205Sharti		p = uni_find_partyx(c, ack->epref.epref, ack->epref.flag);
3193122205Sharti		if (p != NULL) {
3194122205Sharti			handle_bad_drop_cause(c, &ack->cause, 1);
3195122205Sharti			uni_vfy_remove_unknown(c->uni);
3196122205Sharti			switch (uni_verify(c->uni, u->u.hdr.act)) {
3197122205Sharti
3198122205Sharti			  case VFY_CLR:
3199122205Sharti				goto clear;
3200122205Sharti
3201122205Sharti			  case VFY_RAIM:
3202122205Sharti			  case VFY_RAI:
3203122205Sharti				uni_respond_status_verify(c->uni,
3204122205Sharti				    &u->u.hdr.cref, map_callstate(c->cstate),
3205122205Sharti				    &ack->epref, p->state);
3206122205Sharti			  case VFY_I:
3207122205Sharti				goto ignore;
3208122205Sharti
3209122205Sharti			  case VFY_RAP:
3210122205Sharti				uni_respond_status_verify(c->uni,
3211122205Sharti				    &u->u.hdr.cref, map_callstate(c->cstate),
3212122205Sharti				    &ack->epref, UNI_EPSTATE_NULL);
3213122205Sharti			  case VFY_RAPU:
3214122205Sharti			  case VFY_OK:
3215122205Sharti				break;
3216122205Sharti			}
3217122205Sharti			if (legal) {
3218122205Sharti				uni_enq_party(p, SIGP_DROP_PARTY_ACK, 0, m, u);
3219122205Sharti				return;
3220122205Sharti			}
3221122205Sharti			uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3222122205Sharti			    &ack->epref, -1);
3223122205Sharti		}
3224122205Sharti		goto ignore;
3225122205Sharti	}
3226122205Sharti
3227122205Sharti	/* Q.2971: 9.5.3.2.1 last paragraph
3228122205Sharti	 *         9.5.3.2.2 second to last paragraph
3229122205Sharti	 */
3230122205Sharti	(void)uni_verify(c->uni, u->u.hdr.act);
3231122205Sharti	MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_IE_INV);
3232122205Sharti
3233122205Sharti  clear:
3234122205Sharti	uni_vfy_collect_ies(c->uni);
3235122205Sharti	clear_callD(c);
3236122205Sharti	uni_msg_destroy(m);
3237122205Sharti	UNI_FREE(u);
3238122205Sharti	return;
3239122205Sharti
3240122205Sharti  ignore:
3241122205Sharti	uni_msg_destroy(m);
3242122205Sharti	UNI_FREE(u);
3243122205Sharti}
3244122205Sharti
3245122205Sharti/**********************************************************************/
3246122205Sharti
3247122205Sharti/*
3248122205Sharti * Bad or unrecognized message.
3249122205Sharti *
3250122205Sharti * Q.2971:Call-Control-U 35/39
3251122205Sharti */
3252122205Shartivoid
3253122205Shartiuni_bad_message(struct call *c, struct uni_all *u, u_int cause,
3254122205Sharti    struct uni_ie_epref *epref, int ps)
3255122205Sharti{
3256122205Sharti	struct uni_all *resp;
3257122205Sharti	struct party *p;
3258122205Sharti
3259122205Sharti	if ((u->u.hdr.act == UNI_MSGACT_CLEAR &&
3260122205Sharti	    (c->cstate == CALLST_U11 ||
3261122205Sharti	     c->cstate == CALLST_U12 ||
3262122205Sharti	     c->cstate == CALLST_N11 ||
3263122205Sharti	     c->cstate == CALLST_N12)) ||
3264122205Sharti	    u->u.hdr.act == UNI_MSGACT_IGNORE)
3265122205Sharti		return;
3266122205Sharti
3267122205Sharti	MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, cause);
3268122205Sharti	ADD_CAUSE_MTYPE(c->uni->cause, u->mtype);
3269122205Sharti
3270122205Sharti	if (u->u.hdr.act == UNI_MSGACT_CLEAR) {
3271122205Sharti		clear_callD(c);
3272122205Sharti		return;
3273122205Sharti	}
3274122205Sharti
3275122205Sharti	/*
3276122205Sharti	 * Send STATUS
3277122205Sharti	 */
3278122205Sharti	if ((resp = UNI_ALLOC()) != NULL) {
3279122205Sharti		MK_MSG_RESP(resp, UNI_STATUS, &u->u.hdr.cref);
3280122205Sharti		MK_IE_CALLSTATE(resp->u.status.callstate,
3281122205Sharti		    map_callstate(c->cstate));
3282122205Sharti		resp->u.status.cause = c->uni->cause;
3283122205Sharti
3284122205Sharti		if (epref != NULL && IE_ISGOOD(*epref)) {
3285122205Sharti			MK_IE_EPREF(resp->u.status.epref, epref->epref, !epref->flag);
3286122205Sharti			if (ps == -1) {
3287122205Sharti				p = uni_find_party(c, epref);
3288122205Sharti				if (p == NULL)
3289122205Sharti					ps = UNI_EPSTATE_NULL;
3290122205Sharti				else
3291122205Sharti					ps = p->state;
3292122205Sharti			}
3293122205Sharti			MK_IE_EPSTATE(resp->u.status.epstate, ps);
3294122205Sharti		}
3295122205Sharti		(void)uni_send_output(resp, c->uni);
3296122205Sharti
3297122205Sharti		UNI_FREE(resp);
3298122205Sharti	}
3299122205Sharti}
3300122205Sharti
3301122205Sharti/**********************************************************************/
3302122205Sharti
3303122205Sharti/*
3304122205Sharti * Unknown message in any state.
3305122205Sharti *
3306122205Sharti * Q.2971:Call-Control 35/39
3307122205Sharti * Q.2971:Call-Control 36/39
3308122205Sharti */
3309122205Shartistatic void
3310122205Shartiunx_unknown(struct call *c, struct uni_msg *m, struct uni_all *u)
3311122205Sharti{
3312122205Sharti	/*
3313122205Sharti	 * Unrecognized message. Cannot call verify here, because
3314122205Sharti	 * it doesn't know about unrecognized messages.
3315122205Sharti	 */
3316122205Sharti	if (u->u.hdr.act == UNI_MSGACT_CLEAR) {
3317122205Sharti		MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER,
3318122205Sharti		    UNI_CAUSE_MTYPE_NIMPL);
3319122205Sharti		ADD_CAUSE_MTYPE(c->uni->cause, u->mtype);
3320122205Sharti		clear_callD(c);
3321122205Sharti	} else if(u->u.hdr.act == UNI_MSGACT_IGNORE) {
3322122205Sharti		;
3323122205Sharti	} else {
3324122205Sharti		(void)uni_decode_body(m, u, &c->uni->cx);
3325122205Sharti		uni_bad_message(c, u, UNI_CAUSE_MTYPE_NIMPL,
3326122205Sharti		    &u->u.unknown.epref, -1);
3327122205Sharti	}
3328122205Sharti	uni_msg_destroy(m);
3329122205Sharti	UNI_FREE(u);
3330122205Sharti}
3331122205Sharti/**********************************************************************/
3332122205Sharti
3333122205Shartivoid
3334131826Shartiuni_sig_call(struct call *c, enum call_sig sig, uint32_t cookie,
3335122205Sharti    struct uni_msg *msg, struct uni_all *u)
3336122205Sharti{
3337122205Sharti	if (sig >= SIGC_END) {
3338122205Sharti		VERBOSE(c->uni, UNI_FAC_ERR, 1,
3339122205Sharti		    "Signal %d outside of range to Call-Control", sig);
3340122205Sharti		if (msg)
3341122205Sharti			uni_msg_destroy(msg);
3342122205Sharti		if (u)
3343122205Sharti			UNI_FREE(u);
3344122205Sharti		return;
3345122205Sharti	}
3346122205Sharti
3347122205Sharti	VERBOSE(c->uni, UNI_FAC_CALL, 1, "Signal %s in state %s of call %u/%s"
3348122205Sharti	    "; cookie %u", call_sigs[sig], callstates[c->cstate].name, c->cref,
3349122205Sharti	    c->mine ? "mine" : "his", cookie);
3350122205Sharti
3351122205Sharti	switch (sig) {
3352122205Sharti
3353122205Sharti	  case SIGC_LINK_RELEASE_indication:
3354122205Sharti		if (c->cstate == CALLST_U10 || c->cstate == CALLST_N10)
3355122205Sharti			/* Q.2971:Call-Control-U 36/39 */
3356122205Sharti			/* Q.2971:Call-Control-N 20/39 */
3357122205Sharti			un10_link_release_indication(c);
3358122205Sharti		else
3359122205Sharti			/* Q.2971:Call-Control-U 36/39 */
3360122205Sharti			/* Q.2971:Call-Control-N 37/39 */
3361122205Sharti			unx_link_release_indication(c);
3362122205Sharti		break;
3363122205Sharti
3364122205Sharti	  case SIGC_LINK_ESTABLISH_ERROR_indication:
3365122205Sharti		if (c->cstate != CALLST_U10 && c->cstate != CALLST_N10) {
3366122205Sharti			VERBOSE(c->uni, UNI_FAC_ERR, 1,
3367122205Sharti			    "link-establish-error.indication in cs=%s",
3368122205Sharti			    callstates[c->cstate].name);
3369122205Sharti			break;
3370122205Sharti		}
3371122205Sharti		/* Q.2971:Call-Control-U 19/39 */
3372122205Sharti		/* Q.2971:Call-Control-N 20/39 */
3373122205Sharti		un10_link_establish_error_indication(c);
3374122205Sharti		break;
3375122205Sharti
3376122205Sharti	  case SIGC_LINK_ESTABLISH_indication:
3377122205Sharti		switch (c->cstate) {
3378122205Sharti
3379122205Sharti		  case CALLST_U1: case CALLST_N1:
3380122205Sharti		  case CALLST_U3: case CALLST_N3:
3381122205Sharti		  case CALLST_U4: case CALLST_N4:
3382122205Sharti		  case CALLST_U6: case CALLST_N6:
3383122205Sharti		  case CALLST_U7: case CALLST_N7:
3384122205Sharti		  case CALLST_U8: case CALLST_N8:
3385122205Sharti		  case CALLST_U9: case CALLST_N9:
3386122205Sharti			/* Q.2971:Call-Control-U 36/39 */
3387122205Sharti			/* Q.2971:Call-Control-N 37/39 */
3388122205Sharti			unx_link_establish_indication(c);
3389122205Sharti			break;
3390122205Sharti
3391122205Sharti		  case CALLST_U10: case CALLST_N10:
3392122205Sharti			/* Q.2971:Call-Control-U 19/39 */
3393122205Sharti			/* Q.2971:Call-Control-N 20/39 */
3394122205Sharti			un10_link_establish_indication(c);
3395122205Sharti			break;
3396122205Sharti
3397122205Sharti		  case CALLST_U11: case CALLST_N11:
3398122205Sharti		  case CALLST_U12: case CALLST_N12:
3399122205Sharti			/* Q.2971:Call-Control-U 36/39 */
3400122205Sharti			/* Q.2971:Call-Control-N 37/39 */
3401122205Sharti			break;
3402122205Sharti
3403122205Sharti		  default:
3404122205Sharti			VERBOSE(c->uni, UNI_FAC_ERR, 1,
3405122205Sharti			    "link-establish.indication in cs=%s",
3406122205Sharti			    callstates[c->cstate].name);
3407122205Sharti		}
3408122205Sharti		break;
3409122205Sharti
3410122205Sharti	  case SIGC_LINK_ESTABLISH_confirm:
3411122205Sharti		if (c->cstate != CALLST_U10 && c->cstate != CALLST_N10) {
3412122205Sharti			VERBOSE(c->uni, UNI_FAC_ERR, 1,
3413122205Sharti			    "link-establish.confirm in cs=%s",
3414122205Sharti			    callstates[c->cstate].name);
3415122205Sharti			break;
3416122205Sharti		}
3417122205Sharti		/* Q.2971:Call-Control-U 19/39 */
3418122205Sharti		/* Q.2971:Call-Control-N 20/39 */
3419122205Sharti		un10_link_establish_confirm(c);
3420122205Sharti		break;
3421122205Sharti
3422122205Sharti	  case SIGC_UNKNOWN:
3423122205Sharti		/* Q.2971:Call-Control 35/39 */
3424122205Sharti		/* Q.2971:Call-Control 36/39 */
3425122205Sharti		unx_unknown(c, msg, u);
3426122205Sharti		break;
3427122205Sharti
3428122205Sharti	  case SIGC_SETUP:
3429122205Sharti		if (c->cstate != CALLST_NULL) {
3430122205Sharti			(void)uni_decode_body(msg, u, &c->uni->cx);
3431122205Sharti			uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3432122205Sharti			    &u->u.setup.epref, -1);
3433122205Sharti			goto drop;
3434122205Sharti		}
3435122205Sharti		if (c->uni->proto == UNIPROTO_UNI40N)
3436122205Sharti			/* Q.2971:Call-Control-N 4/39 */
3437122205Sharti			un0_setup(c, msg, u, CALLST_N1);
3438122205Sharti		else
3439122205Sharti			/* Q.2971:Call-Control-U 4/39 */
3440122205Sharti			un0_setup(c, msg, u, CALLST_U6);
3441122205Sharti		break;
3442122205Sharti
3443122205Sharti	  case SIGC_CALL_PROC:
3444122205Sharti		if (c->cstate == CALLST_U1) {
3445122205Sharti			/* Q.2971:Call-Control-U 6/39 */
3446122205Sharti			u1n6_call_proc(c, msg, u, CALLST_U3);
3447122205Sharti			break;
3448122205Sharti		}
3449122205Sharti		if (c->cstate == CALLST_N6) {
3450122205Sharti			/* Q.2971:Call-Control-N 11/39 */
3451122205Sharti			u1n6_call_proc(c, msg, u, CALLST_N9);
3452122205Sharti			break;
3453122205Sharti		}
3454122205Sharti		(void)uni_decode_body(msg, u, &c->uni->cx);
3455122205Sharti		uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3456122205Sharti		    &u->u.call_proc.epref, -1);
3457122205Sharti		goto drop;
3458122205Sharti
3459122205Sharti	  case SIGC_ALERTING:
3460122205Sharti		if (c->cstate == CALLST_U1 || c->cstate == CALLST_U3) {
3461122205Sharti			/* Q.2971:Call-Control-U 37/39 (U1) */
3462122205Sharti			/* Q.2971:Call-Control-U 7/39 (U3) */
3463122205Sharti			unx_alerting(c, msg, u, CALLST_U4);
3464122205Sharti			break;
3465122205Sharti		}
3466122205Sharti		if (c->cstate == CALLST_N6) {
3467122205Sharti			/* Q.2971:Call-Control-N 9/39 (N6) */
3468122205Sharti			/* Q.2971:Call-Control-N 17/39 (N9) */
3469122205Sharti			unx_alerting(c, msg, u, CALLST_N7);
3470122205Sharti			break;
3471122205Sharti		}
3472122205Sharti		(void)uni_decode_body(msg, u, &c->uni->cx);
3473122205Sharti		uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3474122205Sharti		    &u->u.alerting.epref, -1);
3475122205Sharti		goto drop;
3476122205Sharti
3477122205Sharti	  case SIGC_CONNECT:
3478122205Sharti		if (c->cstate == CALLST_U1 || c->cstate == CALLST_U3 ||
3479122205Sharti		    c->cstate == CALLST_U4) {
3480122205Sharti			/* Q.2971:Call-Control-U 7-8/39  (U3) */
3481122205Sharti			/* Q.2971:Call-Control-U 11/39   (U4) */
3482122205Sharti			/* Q.2971:Call-Control-U 37/39   (U1) */
3483122205Sharti			unx_connect(c, msg, u, CALLST_U10);
3484122205Sharti			break;
3485122205Sharti		}
3486122205Sharti		if (c->cstate == CALLST_N6 || c->cstate == CALLST_N7 ||
3487122205Sharti		    c->cstate == CALLST_N9) {
3488122205Sharti			/* Q.2971:Call-Control-N 9-10/39 (N6) */
3489122205Sharti			/* Q.2971:Call-Control-N 14/39   (N7) */
3490122205Sharti			/* Q.2971:Call-Control-N 17/39   (N9) */
3491122205Sharti			unx_connect(c, msg, u, CALLST_N8);
3492122205Sharti			break;
3493122205Sharti		}
3494122205Sharti		(void)uni_decode_body(msg, u, &c->uni->cx);
3495122205Sharti		uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3496122205Sharti		    &u->u.connect.epref, -1);
3497122205Sharti		goto drop;
3498122205Sharti
3499122205Sharti	  case SIGC_CONNECT_ACK:
3500122205Sharti		if (c->cstate == CALLST_U8) {
3501122205Sharti			/* Q.2971:Call-Control-U 15-16/39 */
3502122205Sharti			u8_connect_ack(c, msg, u, CALLST_U10);
3503122205Sharti			break;
3504122205Sharti		}
3505122205Sharti		if (c->cstate == CALLST_N10) {
3506122205Sharti			/* Q.2971:Call-Control-N 18/39 */
3507122205Sharti			n10_connect_ack(c, msg, u);
3508122205Sharti			break;
3509122205Sharti		}
3510122205Sharti		uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, NULL, 0);
3511122205Sharti		goto drop;
3512122205Sharti
3513122205Sharti	  case SIGC_RELEASE:
3514122205Sharti		switch (c->cstate) {
3515122205Sharti
3516122205Sharti		  default:
3517122205Sharti			uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, NULL, 0);
3518122205Sharti			goto drop;
3519122205Sharti
3520122205Sharti		  case CALLST_U11:
3521122205Sharti		  case CALLST_N12:
3522122205Sharti			/* Q.2971:Call-Control-U 28/39 */
3523122205Sharti			/* Q.2971:Call-Control-N 30/39 */
3524122205Sharti			u11n12_release(c, msg, u);
3525122205Sharti			break;
3526122205Sharti
3527122205Sharti		  case CALLST_U1:
3528122205Sharti		  case CALLST_U3:
3529122205Sharti		  case CALLST_U4:
3530122205Sharti		  case CALLST_U6:
3531122205Sharti		  case CALLST_U7:
3532122205Sharti		  case CALLST_U8:
3533122205Sharti		  case CALLST_U9:
3534122205Sharti		  case CALLST_U10:
3535122205Sharti		  case CALLST_U12:
3536122205Sharti			/* Q.2971:Call-Control-U 25/39 */
3537122205Sharti			unx_release(c, msg, u, CALLST_U12);
3538122205Sharti			break;
3539122205Sharti
3540122205Sharti		  case CALLST_N1:
3541122205Sharti		  case CALLST_N3:
3542122205Sharti		  case CALLST_N4:
3543122205Sharti		  case CALLST_N6:
3544122205Sharti		  case CALLST_N7:
3545122205Sharti		  case CALLST_N8:
3546122205Sharti		  case CALLST_N9:
3547122205Sharti		  case CALLST_N10:
3548122205Sharti		  case CALLST_N11:
3549122205Sharti			/* Q.2971:Call-Control-N 26/39 */
3550122205Sharti			unx_release(c, msg, u, CALLST_N11);
3551122205Sharti			break;
3552122205Sharti		}
3553122205Sharti		break;
3554122205Sharti
3555122205Sharti	  case SIGC_RELEASE_COMPL:
3556122205Sharti		/* Q.2971:Call-Control-U 25/39 */
3557122205Sharti		/* Q.2971:Call-Control-N 26/39 */
3558122205Sharti		unx_release_compl(c, msg, u);
3559122205Sharti		break;
3560122205Sharti
3561122205Sharti	  case SIGC_NOTIFY:
3562122205Sharti		/* Q.2971:Call-Control-U 18/39 */
3563122205Sharti		/* Q.2971:Call-Control-N 19/39 */
3564122205Sharti		unx_notify(c, msg, u);
3565122205Sharti		break;
3566122205Sharti
3567122205Sharti	  case SIGC_STATUS:
3568122205Sharti		if (c->cstate == CALLST_U11 || c->cstate == CALLST_U12 ||
3569122205Sharti		    c->cstate == CALLST_N11 || c->cstate == CALLST_N12) {
3570122205Sharti			/* Q.2971:Call-Control-U 29/39 (U11) */
3571122205Sharti			/* Q.2971:Call-Control-U 30/39 (U12) */
3572122205Sharti			/* Q.2971:Call-Control-N 29/39 (N11) */
3573122205Sharti			/* Q.2971:Call-Control-N 31/39 (N12) */
3574122205Sharti			un11un12_status(c, msg, u);
3575122205Sharti			break;
3576122205Sharti		}
3577122205Sharti		/* Q.2971:Call-Control-U 32/39 */
3578122205Sharti		/* Q.2971:Call-Control-N 33/39 */
3579122205Sharti		unx_status(c, msg, u);
3580122205Sharti		break;
3581122205Sharti
3582122205Sharti	  case SIGC_STATUS_ENQ:
3583122205Sharti		/* Q.2971:Call-Control-U 31/39 */
3584122205Sharti		/* Q.2971:Call-Control-N 32/39 */
3585122205Sharti		unx_status_enq(c, msg, u);
3586122205Sharti		break;
3587122205Sharti
3588122205Sharti	  case SIGC_ADD_PARTY:
3589122205Sharti		(void)uni_decode_body(msg, u, &c->uni->cx);
3590122205Sharti
3591122205Sharti		if (c->type != CALL_LEAF && c->type != CALL_ROOT) {
3592122205Sharti			uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3593122205Sharti			    &u->u.add_party.epref, UNI_EPSTATE_NULL);
3594122205Sharti			goto drop;
3595122205Sharti		}
3596122205Sharti		switch (c->cstate) {
3597122205Sharti		  case CALLST_U7:
3598122205Sharti		  case CALLST_U8:
3599122205Sharti		  case CALLST_U10:
3600122205Sharti		  case CALLST_N4:
3601122205Sharti		  case CALLST_N10:
3602122205Sharti			/* Q.2971:Call-Control-U 14/39  U7 */
3603122205Sharti			/* Q.2971:Call-Control-U 15/39  U8 */
3604122205Sharti			/* Q.2971:Call-Control-U 21/39  U10 */
3605122205Sharti			/* Q.2971:Call-Control-N 8/39   N4 */
3606122205Sharti			/* Q.2971:Call-Control-N 21/39  N10 */
3607122205Sharti			unx_add_party(c, msg, u, 1);
3608122205Sharti			break;
3609122205Sharti
3610122205Sharti		  default:
3611122205Sharti			unx_add_party(c, msg, u, 0);
3612122205Sharti			goto drop;
3613122205Sharti		}
3614122205Sharti		break;
3615122205Sharti
3616122205Sharti	  case SIGC_PARTY_ALERTING:
3617122205Sharti		(void)uni_decode_body(msg, u, &c->uni->cx);
3618122205Sharti
3619122205Sharti		if (c->type != CALL_ROOT) {
3620122205Sharti			uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3621122205Sharti			    &u->u.party_alerting.epref, -1);
3622122205Sharti			goto drop;
3623122205Sharti		}
3624122205Sharti		switch (c->cstate) {
3625122205Sharti
3626122205Sharti		  default:
3627122205Sharti			/* Q.2971 9.5.3.2.3a) */
3628122205Sharti			unx_party_alerting(c, msg, u, 0);
3629122205Sharti			break;
3630122205Sharti
3631122205Sharti		  case CALLST_U4:
3632122205Sharti		  case CALLST_U10:
3633122205Sharti			/* Q.2971:Call-Control-U 9/39   U4 */
3634122205Sharti			/* Q.2971:Call-Control-U 21/39  U10 */
3635122205Sharti			/* Q.2971:Call-Control-N 12/39  N7 */
3636122205Sharti			/* Q.2971:Call-Control-N 15/39  N8 */
3637122205Sharti			/* Q.2971:Call-Control-N 22/39  N10 */
3638122205Sharti			unx_party_alerting(c, msg, u, 1);
3639122205Sharti			break;
3640122205Sharti		}
3641122205Sharti		break;
3642122205Sharti
3643122205Sharti	  case SIGC_ADD_PARTY_ACK:
3644122205Sharti		(void)uni_decode_body(msg, u, &c->uni->cx);
3645122205Sharti
3646122205Sharti		if (c->type != CALL_ROOT) {
3647122205Sharti			uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3648122205Sharti			    &u->u.add_party_rej.epref, -1);
3649122205Sharti			goto drop;
3650122205Sharti		}
3651122205Sharti		switch (c->cstate) {
3652122205Sharti
3653122205Sharti		  case CALLST_U10:
3654122205Sharti			/* Q.2971:Call-Control-U 21/39 U10 */
3655122205Sharti			/* Q.2971:Call-Control-N 15/39 N8 */
3656122205Sharti			/* Q.2971:Call-Control-N 22/39 N10 */
3657122205Sharti			un10n8_add_party_ack(c, msg, u, 1);
3658122205Sharti			break;
3659122205Sharti
3660122205Sharti		  default:
3661122205Sharti			/* Q.2971 9.5.3.2.3a) */
3662122205Sharti			un10n8_add_party_ack(c, msg, u, 0);
3663122205Sharti			break;
3664122205Sharti		}
3665122205Sharti		break;
3666122205Sharti
3667122205Sharti	  case SIGC_ADD_PARTY_REJ:
3668122205Sharti		(void)uni_decode_body(msg, u, &c->uni->cx);
3669122205Sharti
3670122205Sharti		if (c->type != CALL_ROOT) {
3671122205Sharti			uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3672122205Sharti			    &u->u.add_party_rej.epref, -1);
3673122205Sharti			goto drop;
3674122205Sharti		}
3675122205Sharti		switch (c->cstate) {
3676122205Sharti
3677122205Sharti		  case CALLST_U4:
3678122205Sharti	     	  case CALLST_U10:
3679122205Sharti		  case CALLST_N7:
3680122205Sharti		  case CALLST_N8:
3681122205Sharti		  case CALLST_N10:
3682122205Sharti			/* Q.2971:Call-Control-U 9/39 U4 */
3683122205Sharti			/* Q.2971:Call-Control-U 21/39 U10 */
3684122205Sharti			/* Q.2971:Call-Control-N 12/39 N7 */
3685122205Sharti			/* Q.2971:Call-Control-N 15/39 N8 */
3686122205Sharti			/* Q.2971:Call-Control-N 22/39 N10 */
3687122205Sharti			unx_add_party_rej(c, msg, u, 1);
3688122205Sharti			break;
3689122205Sharti
3690122205Sharti		  default:
3691122205Sharti			/* Q.2971: 9.5.3.2.3b */
3692122205Sharti			unx_add_party_rej(c, msg, u, 0);
3693122205Sharti			break;
3694122205Sharti		}
3695122205Sharti		break;
3696122205Sharti
3697122205Sharti	  case SIGC_DROP_PARTY:
3698122205Sharti		(void)uni_decode_body(msg, u, &c->uni->cx);
3699122205Sharti
3700122205Sharti		if (c->type != CALL_ROOT && c->type != CALL_LEAF) {
3701122205Sharti			uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3702122205Sharti			    &u->u.drop_party.epref, -1);
3703122205Sharti			goto drop;
3704122205Sharti		}
3705122205Sharti		switch (c->cstate) {
3706122205Sharti		  case CALLST_U11:
3707122205Sharti		  case CALLST_U12:
3708122205Sharti		  case CALLST_N11:
3709122205Sharti		  case CALLST_N12:
3710122205Sharti			/* Q.2971:Call-Control-U 28/39 U11 */
3711122205Sharti			/* Q.2971:Call-Control-U 30/39 U12 */
3712122205Sharti			/* Q.2971:Call-Control-N 29/39 N11 */
3713122205Sharti			/* Q.2971:Call-Control-N 30/39 N12 */
3714122205Sharti			goto drop;
3715122205Sharti
3716122205Sharti		  case CALLST_NULL:
3717122205Sharti			uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3718122205Sharti			    &u->u.drop_party.epref, UNI_EPSTATE_NULL);
3719122205Sharti			goto drop;
3720122205Sharti
3721122205Sharti		  case CALLST_U3:
3722122205Sharti		  case CALLST_N3:
3723122205Sharti			/* L3MU_17_38 */
3724122205Sharti			unx_drop_party(c, msg, u, 0);
3725122205Sharti			break;
3726122205Sharti
3727122205Sharti		  case CALLST_U8:
3728122205Sharti			if (c->uni->sb_tb) {
3729122205Sharti				/* L3MU_06_0[3-6] */
3730122205Sharti				unx_drop_party(c, msg, u, 0);
3731122205Sharti				break;
3732122205Sharti			}
3733122205Sharti			/* FALLTHRU */
3734122205Sharti
3735122205Sharti		  default:
3736122205Sharti			/* Q.2971:Call-Control-U 26/39 Ux */
3737122205Sharti			/* Q.2971:Call-Control-U 21/39 U10 */
3738122205Sharti			/* Q.2971:Call-Control-N 27/39 Nx */
3739122205Sharti			/* Q.2971:Call-Control-N 21/39 N10 */
3740122205Sharti			unx_drop_party(c, msg, u, 1);
3741122205Sharti			break;
3742122205Sharti		}
3743122205Sharti		break;
3744122205Sharti
3745122205Sharti	  case SIGC_DROP_PARTY_ACK:
3746122205Sharti		(void)uni_decode_body(msg, u, &c->uni->cx);
3747122205Sharti
3748122205Sharti		if (c->type != CALL_ROOT && c->type != CALL_LEAF) {
3749122205Sharti			uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3750122205Sharti			    &u->u.drop_party_ack.epref, -1);
3751122205Sharti			goto drop;
3752122205Sharti		}
3753122205Sharti		switch (c->cstate) {
3754122205Sharti
3755122205Sharti		  case CALLST_U11:
3756122205Sharti		  case CALLST_U12:
3757122205Sharti			/* Q.2971:Call-Control-U 28/39 U11 */
3758122205Sharti			/* Q.2971:Call-Control-U 30/39 U12 */
3759122205Sharti			/* Q.2971:Call-Control-N 29/39 N11 */
3760122205Sharti			/* Q.2971:Call-Control-N 30/39 N12 */
3761122205Sharti			goto drop;
3762122205Sharti
3763122205Sharti		  case CALLST_NULL:
3764122205Sharti			uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3765122205Sharti			    &u->u.drop_party.epref, UNI_EPSTATE_NULL);
3766122205Sharti			goto drop;
3767122205Sharti
3768122205Sharti		  case CALLST_U4:
3769122205Sharti		  case CALLST_N4:
3770122205Sharti		  case CALLST_U7:
3771122205Sharti		  case CALLST_N7:
3772122205Sharti		  case CALLST_U8:
3773122205Sharti		  case CALLST_N8:
3774122205Sharti		  case CALLST_U10:
3775122205Sharti		  case CALLST_N10:
3776122205Sharti			/* Q.2971:Call-Control-U 26/39 Ux */
3777122205Sharti			/* Q.2971:Call-Control-U 21/39 U10 */
3778122205Sharti			/* Q.2971:Call-Control-N 27/39 Nx */
3779122205Sharti			/* Q.2971:Call-Control-N 22/39 N10 */
3780122205Sharti			unx_drop_party_ack(c, msg, u, 1);
3781122205Sharti			break;
3782122205Sharti
3783122205Sharti		  default:
3784122205Sharti			/* Q.2971 10.5 4th paragraph */
3785122205Sharti			unx_drop_party_ack(c, msg, u, 0);
3786122205Sharti			break;
3787122205Sharti		}
3788122205Sharti		break;
3789122205Sharti
3790122205Sharti	  case SIGC_COBISETUP:	/* XXX */
3791122205Sharti		unx_unknown(c, msg, u);
3792122205Sharti		break;
3793122205Sharti
3794122205Sharti	  /*
3795122205Sharti	   * User signals
3796122205Sharti	   */
3797122205Sharti	  case SIGC_SETUP_request:
3798122205Sharti		if (c->cstate == CALLST_NULL) {
3799122205Sharti			/* Q.2971:Call-Control-U 4/39 (U0) */
3800122205Sharti			/* Q.2971:Call-Control-N 4/39 (N0) */
3801122205Sharti			if (c->uni->proto == UNIPROTO_UNI40N)
3802122205Sharti				un0_setup_request(c, msg, cookie, CALLST_N6);
3803122205Sharti			else
3804122205Sharti				un0_setup_request(c, msg, cookie, CALLST_U1);
3805122205Sharti			break;
3806122205Sharti		}
3807122205Sharti		VERBOSE(c->uni, UNI_FAC_ERR, 1, "setup.request in cs=%s",
3808122205Sharti		    callstates[c->cstate].name);
3809122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
3810122205Sharti		uni_msg_destroy(msg);
3811122205Sharti		break;
3812122205Sharti
3813122205Sharti	  case SIGC_SETUP_response:
3814122205Sharti		if (c->cstate == CALLST_U6 || c->cstate == CALLST_U9 ||
3815122205Sharti		    c->cstate == CALLST_U7) {
3816122205Sharti			/* Q.2971:Call-Control-U 13/39	(U6) */
3817122205Sharti			/* Q.2971:Call-Control-U 14/39	(U7) */
3818122205Sharti			/* Q.2971:Call-Control-U 17/39	(U9) */
3819122205Sharti			unx_setup_response(c, msg, cookie, CALLST_U8);
3820122205Sharti			break;
3821122205Sharti		}
3822122205Sharti		if (c->cstate == CALLST_N1 || c->cstate == CALLST_N3 ||
3823122205Sharti		    c->cstate == CALLST_N4) {
3824122205Sharti			/* Q.2971:Call-Control-N 39/39  (N1) */
3825122205Sharti			/* Q.2971:Call-Control-N 7/39   (N3) */
3826122205Sharti			/* Q.2971:Call-Control-N 8/39   (N4) */
3827122205Sharti			unx_setup_response(c, msg, cookie, CALLST_N10);
3828122205Sharti			break;
3829122205Sharti		}
3830122205Sharti		VERBOSE(c->uni, UNI_FAC_ERR, 1, "setup.response in cs=%s",
3831122205Sharti		    callstates[c->cstate].name);
3832122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
3833122205Sharti		uni_msg_destroy(msg);
3834122205Sharti		break;
3835122205Sharti
3836122205Sharti	  case SIGC_SETUP_COMPLETE_request:
3837122205Sharti		if (c->cstate == CALLST_N8) {
3838122205Sharti			/* Q.2971:Call-Control-N 15/39 (N8) */
3839122205Sharti			n8_setup_compl_request(c, msg, cookie, CALLST_N10);
3840122205Sharti			break;
3841122205Sharti		}
3842122205Sharti		VERBOSE(c->uni, UNI_FAC_ERR, 1, "setup_compl.request in cs=%s",
3843122205Sharti		    callstates[c->cstate].name);
3844122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
3845122205Sharti		uni_msg_destroy(msg);
3846122205Sharti		break;
3847122205Sharti
3848122205Sharti	  case SIGC_PROCEEDING_request:
3849122205Sharti		if (c->cstate == CALLST_U6) {
3850122205Sharti			/* Q.2971:Call-Control-U 12/39 (U6) */
3851122205Sharti			u6n1_proceeding_request(c, msg, cookie, CALLST_U9);
3852122205Sharti			break;
3853122205Sharti		}
3854122205Sharti		if (c->cstate == CALLST_N1) {
3855122205Sharti			/* Q.2971:Call-Control-N 6/39 (N1) */
3856122205Sharti			u6n1_proceeding_request(c, msg, cookie, CALLST_N3);
3857122205Sharti			break;
3858122205Sharti		}
3859122205Sharti		VERBOSE(c->uni, UNI_FAC_ERR, 1, "proceeding.request in cs=%s",
3860122205Sharti		    callstates[c->cstate].name);
3861122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
3862122205Sharti		uni_msg_destroy(msg);
3863122205Sharti		break;
3864122205Sharti
3865122205Sharti	  case SIGC_ALERTING_request:
3866122205Sharti		if (c->cstate == CALLST_U6 || c->cstate == CALLST_U9) {
3867122205Sharti			/* Q.2971:Call-Control-U 13/39 (U6) */
3868122205Sharti			/* Q.2971:Call-Control-U 17/39 (U9) */
3869122205Sharti			unx_alerting_request(c, msg, cookie, CALLST_U7);
3870122205Sharti			break;
3871122205Sharti		}
3872131826Sharti		if (c->cstate == CALLST_N1 || c->cstate == CALLST_N3) {
3873122205Sharti			/* Q.2971:Call-Control-N 38/39 (N1) */
3874122205Sharti			/* Q.2971:Call-Control-N 7/39  (N3) */
3875122205Sharti			unx_alerting_request(c, msg, cookie, CALLST_N4);
3876122205Sharti			break;
3877122205Sharti		}
3878122205Sharti		VERBOSE(c->uni, UNI_FAC_ERR, 1, "alerting.request in cs=%s",
3879122205Sharti		    callstates[c->cstate].name);
3880122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
3881122205Sharti		uni_msg_destroy(msg);
3882122205Sharti		break;
3883122205Sharti
3884122205Sharti	  case SIGC_RELEASE_request:
3885122205Sharti		switch (c->cstate) {
3886122205Sharti
3887122205Sharti		  case CALLST_U1:
3888122205Sharti		  case CALLST_U3:
3889122205Sharti		  case CALLST_U4:
3890122205Sharti		  case CALLST_U6:
3891122205Sharti		  case CALLST_U7:
3892122205Sharti		  case CALLST_U8:
3893122205Sharti		  case CALLST_U9:
3894122205Sharti		  case CALLST_U10:
3895122205Sharti			/* Q.2971:Call-Control-U 27/39 */
3896122205Sharti			unx_release_request(c, msg, cookie, CALLST_U11);
3897122205Sharti			break;
3898122205Sharti
3899122205Sharti		  case CALLST_N1:
3900122205Sharti		  case CALLST_N3:
3901122205Sharti		  case CALLST_N4:
3902122205Sharti		  case CALLST_N6:
3903122205Sharti		  case CALLST_N7:
3904122205Sharti		  case CALLST_N8:
3905122205Sharti		  case CALLST_N9:
3906122205Sharti		  case CALLST_N10:
3907122205Sharti			/* Q.2971:Call-Control-N 28/39 */
3908122205Sharti			unx_release_request(c, msg, cookie, CALLST_N12);
3909122205Sharti			break;
3910122205Sharti
3911122205Sharti		  case CALLST_U11:
3912122205Sharti		  case CALLST_U12:
3913122205Sharti		  case CALLST_N11:
3914122205Sharti		  case CALLST_N12:
3915122205Sharti		  case CALLST_NULL:
3916122205Sharti			VERBOSE(c->uni, UNI_FAC_ERR, 1,
3917122205Sharti			    "release.request in cs=%s",
3918122205Sharti			    callstates[c->cstate].name);
3919122205Sharti			uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE,
3920122205Sharti			    cookie);
3921122205Sharti			uni_msg_destroy(msg);
3922122205Sharti			break;
3923122205Sharti		}
3924122205Sharti		break;
3925122205Sharti
3926122205Sharti	  case SIGC_RELEASE_response:
3927122205Sharti		if (c->cstate == CALLST_U6 || c->cstate == CALLST_U12 ||
3928122205Sharti		    c->cstate == CALLST_N1 || c->cstate == CALLST_N11) {
3929122205Sharti			/* Q.2971:Call-Control-U 12/39 (U6) */
3930122205Sharti			/* Q.2971:Call-Control-U 30/39 (U12) */
3931122205Sharti			/* Q.2971:Call-Control-N 6/39  (N1) */
3932122205Sharti			/* Q.2971:Call-Control-N 29/39 (N11) */
3933122205Sharti			unx_release_response(c, msg, cookie);
3934122205Sharti			break;
3935122205Sharti		}
3936122205Sharti		VERBOSE(c->uni, UNI_FAC_ERR, 1, "release.response in cs=%s",
3937122205Sharti		    callstates[c->cstate].name);
3938122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
3939122205Sharti		uni_msg_destroy(msg);
3940122205Sharti		break;
3941122205Sharti
3942122205Sharti	  case SIGC_NOTIFY_request:
3943122205Sharti		/* Q.2971:Call-Control-U 18/39 */
3944122205Sharti		/* Q.2971:Call-Control-N 19/39 */
3945122205Sharti		unx_notify_request(c, msg, cookie);
3946122205Sharti		break;
3947122205Sharti
3948122205Sharti	  case SIGC_STATUS_ENQUIRY_request:
3949122205Sharti		/* Q.2971:Call-Control-U 31/39 */
3950122205Sharti		/* Q.2971:Call-Control-N 32/39 */
3951122205Sharti		unx_status_enquiry_request(c, msg, cookie);
3952122205Sharti		break;
3953122205Sharti
3954122205Sharti	  case SIGC_ADD_PARTY_request:
3955122205Sharti		if (c->cstate == CALLST_U4 || c->cstate == CALLST_U10 ||
3956122205Sharti		    c->cstate == CALLST_N7 || c->cstate == CALLST_N10) {
3957122205Sharti			/* Q.2971:Call-Control-U 9-10/39 (U4) */
3958122205Sharti			/* Q.2971:Call-Control-U 21/39 (U10) */
3959122205Sharti			/* Q.2971:Call-Control-N 12/39 (N7) */
3960122205Sharti			/* Q.2971:Call-Control-N 22/39 (N10) */
3961122205Sharti			unx_add_party_request(c, msg, cookie);
3962122205Sharti			break;
3963122205Sharti		}
3964122205Sharti		VERBOSE(c->uni, UNI_FAC_ERR, 1, "add-party.request in cs=%s",
3965122205Sharti		    callstates[c->cstate].name);
3966122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
3967122205Sharti		uni_msg_destroy(msg);
3968122205Sharti		break;
3969122205Sharti
3970122205Sharti	  case SIGC_PARTY_ALERTING_request:
3971122205Sharti		if (c->cstate == CALLST_U7 || c->cstate == CALLST_U8 ||
3972122205Sharti		    c->cstate == CALLST_U10 ||
3973122205Sharti		    c->cstate == CALLST_N4 || c->cstate == CALLST_N10) {
3974122205Sharti			/* Q.2971:Call-Control-U 14/39 U7 */
3975122205Sharti			/* Q.2971:Call-Control-U 15/39 U8 */
3976122205Sharti			/* Q.2971:Call-Control-U 21/39 U10 */
3977122205Sharti			/* Q.2971:Call-Control-N 8/39  N4 */
3978122205Sharti			/* Q.2971:Call-Control-N 22/39 N10 */
3979122205Sharti			unx_party_alerting_request(c, msg, cookie);
3980122205Sharti			break;
3981122205Sharti		}
3982122205Sharti		VERBOSE(c->uni, UNI_FAC_ERR, 1,
3983122205Sharti		    "party-alerting.request in cs=%s",
3984122205Sharti		    callstates[c->cstate].name);
3985122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
3986122205Sharti		uni_msg_destroy(msg);
3987122205Sharti		break;
3988122205Sharti
3989122205Sharti	  case SIGC_ADD_PARTY_ACK_request:
3990122205Sharti		if (c->cstate == CALLST_U10 || c->cstate == CALLST_N10) {
3991122205Sharti			/* Q.2971:Call-Control-U 21/39 (U10) */
3992122205Sharti			/* Q.2971:Call-Control-N 22/39 (N10)*/
3993122205Sharti			un10_add_party_ack_request(c, msg, cookie);
3994122205Sharti			break;
3995122205Sharti		}
3996122205Sharti		VERBOSE(c->uni, UNI_FAC_ERR, 1,
3997122205Sharti		    "add-party-ack.request in cs=%s",
3998122205Sharti		    callstates[c->cstate].name);
3999122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
4000122205Sharti		uni_msg_destroy(msg);
4001122205Sharti		break;
4002122205Sharti
4003122205Sharti	  case SIGC_ADD_PARTY_REJ_request:
4004122205Sharti		if (c->cstate == CALLST_U7 || c->cstate == CALLST_U8 ||
4005122205Sharti		    c->cstate == CALLST_U10 ||
4006122205Sharti		    c->cstate == CALLST_N4 || c->cstate == CALLST_N10) {
4007122205Sharti			/* Q.2971:Call-Control-U 14/39 U7 */
4008122205Sharti			/* Q.2971:Call-Control-U 15/39 U8 */
4009122205Sharti			/* Q.2971:Call-Control-U 21/39 U10 */
4010122205Sharti			/* Q.2971:Call-Control-N 8/39  N4 */
4011122205Sharti			/* Q.2971:Call-Control-N 22/39 N10 */
4012122205Sharti			unx_add_party_rej_request(c, msg, cookie);
4013122205Sharti			break;
4014122205Sharti		}
4015122205Sharti		VERBOSE(c->uni, UNI_FAC_ERR, 1,
4016122205Sharti		    "add-party-rej.request in cs=%s",
4017122205Sharti		    callstates[c->cstate].name);
4018122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
4019122205Sharti		uni_msg_destroy(msg);
4020122205Sharti		break;
4021122205Sharti
4022122205Sharti	  case SIGC_DROP_PARTY_request:
4023122205Sharti		if (c->cstate != CALLST_U11 && c->cstate != CALLST_U12 &&
4024122205Sharti		    c->cstate != CALLST_N11 && c->cstate != CALLST_N12 &&
4025122205Sharti		    c->cstate != CALLST_NULL) {
4026122205Sharti			/* Q.2971:Call-Control-U 21/39 U10 */
4027122205Sharti			/* Q.2971:Call-Control-U 26/39 U1-U9 */
4028122205Sharti			/* Q.2971:Call-Control-N 22/39 N10 */
4029122205Sharti			/* Q.2971:Call-Control-N 27/39 N1-N9 */
4030122205Sharti			unx_drop_party_request(c, msg, cookie);
4031122205Sharti			break;
4032122205Sharti		}
4033122205Sharti		VERBOSE(c->uni, UNI_FAC_ERR, 1, "drop-party.request in cs=%s",
4034122205Sharti		    callstates[c->cstate].name);
4035122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
4036122205Sharti		uni_msg_destroy(msg);
4037122205Sharti		break;
4038122205Sharti
4039122205Sharti	  case SIGC_DROP_PARTY_ACK_request:
4040122205Sharti		if (c->cstate != CALLST_U11 && c->cstate != CALLST_U12 &&
4041122205Sharti		    c->cstate != CALLST_N11 && c->cstate != CALLST_N12 &&
4042122205Sharti		    c->cstate != CALLST_NULL) {
4043122205Sharti			/* Q.2971:Call-Control-U 21/39 U10 */
4044122205Sharti			/* Q.2971:Call-Control-U 26/39 U1-U9 */
4045122205Sharti			/* Q.2971:Call-Control-N 22/39 N10 */
4046122205Sharti			/* Q.2971:Call-Control-N 27/39 N1-N9 */
4047122205Sharti			unx_drop_party_ack_request(c, msg, cookie);
4048122205Sharti			break;
4049122205Sharti		}
4050122205Sharti		VERBOSE(c->uni, UNI_FAC_ERR, 1,
4051122205Sharti		    "drop-party-ack.request in cs=%s",
4052122205Sharti		    callstates[c->cstate].name);
4053122205Sharti		uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
4054122205Sharti		uni_msg_destroy(msg);
4055122205Sharti		break;
4056122205Sharti
4057122205Sharti	  case SIGC_ABORT_CALL_request:
4058122205Sharti	    {
4059122205Sharti		struct uni *uni = c->uni;
4060122205Sharti
4061122205Sharti		uni_destroy_call(c, 0);
4062122205Sharti		uniapi_uni_error(uni, UNIAPI_OK, cookie, UNI_CALLSTATE_U0);
4063122205Sharti		break;
4064122205Sharti	    }
4065122205Sharti
4066122205Sharti	  /*
4067122205Sharti	   * Timers
4068122205Sharti	   */
4069122205Sharti	  case SIGC_T301:
4070122205Sharti		if (c->cstate == CALLST_U4 || c->cstate == CALLST_N7) {
4071122205Sharti			/* Q.2971:Call-Control-U Missing */
4072122205Sharti			/* Q.2971:Call-Control-N 14/39 */
4073122205Sharti			u4n7_t301(c);
4074122205Sharti			break;
4075122205Sharti		}
4076122205Sharti		VERBOSE(c->uni, UNI_FAC_ERR, 1, "T301 in cs=%s",
4077122205Sharti		    callstates[c->cstate].name);
4078122205Sharti		break;
4079122205Sharti
4080122205Sharti	  case SIGC_T303:
4081122205Sharti		if (c->cstate == CALLST_U1 || c->cstate == CALLST_N6) {
4082122205Sharti			/* Q.2971:Call-Control-U 6/39 */
4083122205Sharti			/* Q.2971:Call-Control-N 11/39 */
4084122205Sharti			u1n6_t303(c);
4085122205Sharti			break;
4086122205Sharti		}
4087122205Sharti		VERBOSE(c->uni, UNI_FAC_ERR, 1, "T303 in cs=%s",
4088122205Sharti		    callstates[c->cstate].name);
4089122205Sharti		break;
4090122205Sharti
4091122205Sharti	  case SIGC_T308:
4092122205Sharti		if (c->cstate == CALLST_U11 || c->cstate == CALLST_N12) {
4093122205Sharti			/* Q.2971:Call-Control-U 28/39 */
4094122205Sharti			/* Q.2971:Call-Control-N 30/39 */
4095122205Sharti			u11n12_t308(c);
4096122205Sharti			break;
4097122205Sharti		}
4098122205Sharti		VERBOSE(c->uni, UNI_FAC_ERR, 1, "T308 in cs=%s",
4099122205Sharti		    callstates[c->cstate].name);
4100122205Sharti		break;
4101122205Sharti
4102122205Sharti	  case SIGC_T310:
4103122205Sharti		if (c->cstate == CALLST_U3 || c->cstate == CALLST_N9) {
4104122205Sharti			/* Q.2971:Call-Control-U 7/39 */
4105122205Sharti			/* Q.2971:Call-Control-N 17/39 */
4106122205Sharti			u3n9_t310(c);
4107122205Sharti			break;
4108122205Sharti		}
4109122205Sharti		VERBOSE(c->uni, UNI_FAC_ERR, 1, "T310 in cs=%s",
4110122205Sharti		    callstates[c->cstate].name);
4111122205Sharti		break;
4112122205Sharti
4113122205Sharti	  case SIGC_T313:
4114122205Sharti		if (c->cstate == CALLST_U8) {
4115122205Sharti			/* Q.2971:Call-Control-U 15/39 */
4116122205Sharti			u8_t313(c);
4117122205Sharti			break;
4118122205Sharti		}
4119122205Sharti		VERBOSE(c->uni, UNI_FAC_ERR, 1, "T313 in cs=%s",
4120122205Sharti		    callstates[c->cstate].name);
4121122205Sharti		break;
4122122205Sharti
4123122205Sharti	  case SIGC_T322:
4124122205Sharti		/* Q.2971:Call-Control-U 34/39 */
4125122205Sharti		/* Q.2971:Call-Control-N 35/39 */
4126122205Sharti		unx_t322(c);
4127122205Sharti		break;
4128122205Sharti
4129122205Sharti	  case SIGC_CALL_DELETE:
4130122205Sharti		CALL_FREE(c);
4131122205Sharti		break;
4132122205Sharti
4133122205Sharti	  /*
4134122205Sharti	   * Party-Control
4135122205Sharti	   */
4136122205Sharti	  case SIGC_DROP_PARTY_indication:
4137122205Sharti		if (c->uni->proto == UNIPROTO_UNI40U)
4138122205Sharti			/* Q.2971:Call-Control-U 23/39 */
4139122205Sharti			ux_drop_party_indication(c, msg);
4140122205Sharti		else
4141122205Sharti			/* Q.2971:Call-Control-N 23/39 */
4142122205Sharti			nx_drop_party_indication(c, msg);
4143122205Sharti		break;
4144122205Sharti
4145122205Sharti	  case SIGC_DROP_PARTY_ACK_indication:
4146122205Sharti		if (c->uni->proto == UNIPROTO_UNI40U)
4147122205Sharti			/* Q.2971:Call-Control-U 23/39 */
4148122205Sharti			ux_drop_party_ack_indication(c, msg);
4149122205Sharti		else
4150122205Sharti			/* Q.2971:Call-Control-N 23/39 */
4151122205Sharti			nx_drop_party_ack_indication(c, msg);
4152122205Sharti		break;
4153122205Sharti
4154122205Sharti	  case SIGC_ADD_PARTY_REJ_indication:
4155122205Sharti		if (c->uni->proto == UNIPROTO_UNI40U)
4156122205Sharti			/* Q.2971:Call-Control-U 23/39 */
4157122205Sharti			ux_add_party_rej_indication(c, msg);
4158122205Sharti		else
4159122205Sharti			/* Q.2971:Call-Control-N 23/39 */
4160122205Sharti			nx_add_party_rej_indication(c, msg);
4161122205Sharti		break;
4162122205Sharti
4163122205Sharti
4164122205Sharti	  case SIGC_SEND_DROP_PARTY:
4165122205Sharti		/* Q.2971:Call-Control-U 21/39 */
4166122205Sharti		/* Q.2971:Call-Control-U 25/39 */
4167122205Sharti		if (uni_party_act_count(c, 2) != 0)
4168122205Sharti			(void)uni_send_output(u, c->uni);
4169122205Sharti		else if(c->cstate != CALLST_U11) {
4170122205Sharti			c->uni->cause = u->u.drop_party.cause;
4171122205Sharti			clear_callD(c);
4172122205Sharti		}
4173122205Sharti		UNI_FREE(u);
4174122205Sharti		break;
4175122205Sharti
4176122205Sharti	  case SIGC_SEND_DROP_PARTY_ACK:
4177122205Sharti		/* Q.2971:Call-Control-U 21/39 */
4178122205Sharti		/* Q.2971:Call-Control-U 25/39 */
4179122205Sharti		if (uni_party_act_count(c, 2) != 0)
4180122205Sharti			(void)uni_send_output(u, c->uni);
4181122205Sharti		else if (c->cstate != CALLST_U11) {
4182122205Sharti			c->uni->cause = u->u.drop_party_ack.cause;
4183122205Sharti			clear_callD(c);
4184122205Sharti		}
4185122205Sharti		UNI_FREE(u);
4186122205Sharti		break;
4187122205Sharti
4188122205Sharti	  case SIGC_SEND_ADD_PARTY_REJ:
4189122205Sharti		/* Q.2971:Call-Control-U 21/39 */
4190122205Sharti		/* Q.2971:Call-Control-U 24/39 */
4191122205Sharti		unx_send_add_party_rej(c, u);
4192122205Sharti		break;
4193122205Sharti
4194122205Sharti	  case SIGC_SEND_STATUS_ENQ:
4195122205Sharti		/* Q.2971:Call-Control-U 21/39 */
4196122205Sharti		/* Q.2971:Call-Control-U 25/39 */
4197122205Sharti		unx_send_party_status_enq(c, u);
4198122205Sharti		break;
4199122205Sharti
4200122205Sharti	  case SIGC_PARTY_DESTROYED:
4201122205Sharti		c->uni->funcs->uni_output(c->uni, c->uni->arg,
4202122205Sharti		    UNIAPI_PARTY_DESTROYED, cookie, msg);
4203122205Sharti		break;
4204122205Sharti
4205122205Sharti	  case SIGC_END:
4206122205Sharti		break;
4207122205Sharti	}
4208122205Sharti
4209122205Sharti	return;
4210122205Sharti
4211122205Sharti  drop:
4212122205Sharti	/*
4213122205Sharti	 * This is for SAAL message signals that should be dropped.
4214122205Sharti	 */
4215122205Sharti	uni_msg_destroy(msg);
4216122205Sharti	UNI_FREE(u);
4217122205Sharti}
4218122205Sharti
4219122205Sharti/**********************************************************************/
4220122205Sharti
4221122205Sharti/*
4222122205Sharti * Timeout functions
4223122205Sharti */
4224122205Shartistatic void
4225122205Shartit308_func(struct call *c)
4226122205Sharti{
4227122205Sharti	uni_enq_call(c, SIGC_T308, 0, NULL, NULL);
4228122205Sharti}
4229122205Shartistatic void
4230122205Shartit303_func(struct call *c)
4231122205Sharti{
4232122205Sharti	uni_enq_call(c, SIGC_T303, 0, NULL, NULL);
4233122205Sharti}
4234122205Shartistatic void
4235122205Shartit301_func(struct call *c)
4236122205Sharti{
4237122205Sharti	uni_enq_call(c, SIGC_T301, 0, NULL, NULL);
4238122205Sharti}
4239122205Shartistatic void
4240122205Shartit310_func(struct call *c)
4241122205Sharti{
4242122205Sharti	uni_enq_call(c, SIGC_T310, 0, NULL, NULL);
4243122205Sharti}
4244122205Shartistatic void
4245122205Shartit313_func(struct call *c)
4246122205Sharti{
4247122205Sharti	uni_enq_call(c, SIGC_T313, 0, NULL, NULL);
4248122205Sharti}
4249122205Sharti
4250122205Shartistatic void
4251122205Shartit322_func(struct call *c)
4252122205Sharti{
4253122205Sharti	uni_enq_call(c, SIGC_T322, 0, NULL, NULL);
4254122205Sharti}
4255122205Sharti
4256122205Sharti/**********************************************************************/
4257122205Sharti
4258122205Sharti/*
4259122205Sharti * Check whether the peer state is compatible with our state.
4260122205Sharti * Return the new callstate we should go to (either U0 or the current
4261122205Sharti * state).
4262122205Sharti * None of the state is U0 here. My state is not U11 or U12.
4263122205Sharti *
4264122205Sharti * Well, this turns out to be not so easy: the status enquiry could have
4265122205Sharti * been sent before we changed into the current state - the status will
4266122205Sharti * report a previous state without anything been lost.
4267122205Sharti *
4268122205Sharti * Incoming states are incompatible with outgoing states. Everything is ok.
4269122205Sharti */
4270122205Shartistatic enum call_state
4271122205Shartistate_compat(struct call *c, enum uni_callstate peer)
4272122205Sharti{
4273122205Sharti	if ((c->cstate == CALLST_U1 ||
4274122205Sharti	     c->cstate == CALLST_U3 ||
4275122205Sharti	     c->cstate == CALLST_U4) &&
4276122205Sharti	   (peer == UNI_CALLSTATE_N6 ||
4277122205Sharti	    peer == UNI_CALLSTATE_N7 ||
4278122205Sharti	    peer == UNI_CALLSTATE_N8 ||
4279122205Sharti	    peer == UNI_CALLSTATE_N9))
4280122205Sharti		return (CALLST_NULL);
4281122205Sharti
4282122205Sharti	if ((c->cstate == CALLST_N6 ||
4283122205Sharti	     c->cstate == CALLST_N7 ||
4284122205Sharti	     c->cstate == CALLST_N8 ||
4285122205Sharti	     c->cstate == CALLST_N9) &&
4286122205Sharti	    (peer == UNI_CALLSTATE_U1 ||
4287122205Sharti	     peer == UNI_CALLSTATE_U3 ||
4288122205Sharti	     peer == UNI_CALLSTATE_U4))
4289122205Sharti		return (CALLST_NULL);
4290122205Sharti
4291122205Sharti	if ((peer == UNI_CALLSTATE_N1 ||
4292122205Sharti	     peer == UNI_CALLSTATE_N3 ||
4293122205Sharti	     peer == UNI_CALLSTATE_N4) &&
4294122205Sharti	   (c->cstate == CALLST_U6 ||
4295122205Sharti	    c->cstate == CALLST_U7 ||
4296122205Sharti	    c->cstate == CALLST_U8 ||
4297122205Sharti	    c->cstate == CALLST_N9))
4298122205Sharti		return (CALLST_NULL);
4299122205Sharti
4300122205Sharti	if ((peer == UNI_CALLSTATE_U6 ||
4301122205Sharti	     peer == UNI_CALLSTATE_U7 ||
4302122205Sharti	     peer == UNI_CALLSTATE_U8 ||
4303122205Sharti	     peer == UNI_CALLSTATE_U9) &&
4304122205Sharti	   (c->cstate == CALLST_N1 ||
4305122205Sharti	    c->cstate == CALLST_N3 ||
4306122205Sharti	    c->cstate == CALLST_N4))
4307122205Sharti		return (CALLST_NULL);
4308122205Sharti
4309122205Sharti	return (c->cstate);
4310122205Sharti}
4311