1/*
2 * Copyright (c) 1996-2003
3 *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4 * 	All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * Author: Hartmut Brandt <harti@freebsd.org>
28 *
29 * $Begemot: libunimsg/netnatm/sig/sig_call.c,v 1.65 2004/08/05 07:11:00 brandt Exp $
30 *
31 * Call instance handling
32 *
33 * Note:
34 *	In all functions that handle messages from the user or from
35 *	the SAAL, commit memory allocation always at the begin of the
36 *	function. If allocation fails, ignore saal messages and
37 *	respond with an error to user messages.
38 */
39
40#include <netnatm/unimsg.h>
41#include <netnatm/saal/sscfudef.h>
42#include <netnatm/msg/unistruct.h>
43#include <netnatm/msg/unimsglib.h>
44#include <netnatm/sig/uni.h>
45
46#include <netnatm/sig/unipriv.h>
47#include <netnatm/sig/unimkmsg.h>
48#include <netnatm/sig/unimsgcpy.h>
49
50static enum call_state state_compat(struct call *, enum uni_callstate);
51static void respond_drop_party_ack(struct call *, struct uni_ie_epref *, u_int);
52
53
54#define DEF_PRIV_SIG(NAME, FROM)	[SIG##NAME] =	"SIG"#NAME,
55static const char *const call_sigs[] = {
56	DEF_CALL_SIGS
57};
58#undef DEF_PRIV_SIG
59
60TIMER_FUNC_CALL(t308, t308_func)
61TIMER_FUNC_CALL(t303, t303_func)
62TIMER_FUNC_CALL(t301, t301_func)
63TIMER_FUNC_CALL(t310, t310_func)
64TIMER_FUNC_CALL(t313, t313_func)
65TIMER_FUNC_CALL(t322, t322_func)
66
67const struct callstates callstates[] = {
68	[CALLST_NULL] =	{ "NU0",	UNI_CALLSTATE_U0 },
69	[CALLST_U1] =	{ "U1",		UNI_CALLSTATE_U1 },
70	[CALLST_U3] =	{ "U3",		UNI_CALLSTATE_U3 },
71	[CALLST_U4] =	{ "U4",		UNI_CALLSTATE_U4 },
72	[CALLST_U6] =	{ "U6",		UNI_CALLSTATE_U6 },
73	[CALLST_U7] =	{ "U7",		UNI_CALLSTATE_U7 },
74	[CALLST_U8] =	{ "U8",		UNI_CALLSTATE_U8 },
75	[CALLST_U9] =	{ "U9",		UNI_CALLSTATE_U9 },
76	[CALLST_U10] =	{ "U10",	UNI_CALLSTATE_U10 },
77	[CALLST_U11] =	{ "U11",	UNI_CALLSTATE_U11 },
78	[CALLST_U12] =	{ "U12",	UNI_CALLSTATE_U12 },
79	[CALLST_N1] =	{ "N1",		UNI_CALLSTATE_N1 },
80	[CALLST_N3] =	{ "N3",		UNI_CALLSTATE_N3 },
81	[CALLST_N4] =	{ "N4",		UNI_CALLSTATE_N4 },
82	[CALLST_N6] =	{ "N6",		UNI_CALLSTATE_N6 },
83	[CALLST_N7] =	{ "N7",		UNI_CALLSTATE_N7 },
84	[CALLST_N8] =	{ "N8",		UNI_CALLSTATE_N8 },
85	[CALLST_N9] =	{ "N9",		UNI_CALLSTATE_N9 },
86	[CALLST_N10] =	{ "N10",	UNI_CALLSTATE_N10 },
87	[CALLST_N11] =	{ "N11",	UNI_CALLSTATE_N11 },
88	[CALLST_N12] =	{ "N12",	UNI_CALLSTATE_N12 },
89};
90
91static void unx_send_add_party_rej(struct call *c, struct uni_all *u);
92
93static __inline void
94set_call_state(struct call *c, enum call_state state)
95{
96	ASSERT(state == CALLST_NULL ||
97	    (c->uni->proto == UNIPROTO_UNI40U &&
98	     (state >= CALLST_U1 && state <= CALLST_U12)) ||
99	    (c->uni->proto == UNIPROTO_UNI40N &&
100	     (state >= CALLST_N1 && state <= CALLST_N12)),
101	    ("setting wrong callstate for proto %u: %u", c->uni->proto, state));
102
103	if (c->cstate != state) {
104		VERBOSE(c->uni, UNI_FAC_CALL, 1, "call %d/%d %s -> %s",
105		    c->cref, c->mine, callstates[c->cstate].name,
106		    callstates[state].name);
107		c->cstate = state;
108	}
109}
110
111static enum uni_callstate
112map_callstate(enum call_state state)
113{
114	return (callstates[state].ext);
115}
116
117/*
118 * Find the call. Assume, that the cref is one of a message just received.
119 * That is, if the call reference flag is 0 it is his call, if it is 1 it
120 * is my call.
121 */
122struct call *
123uni_find_call(struct uni *uni, struct uni_cref *cref)
124{
125	struct call *c;
126
127	TAILQ_FOREACH(c, &uni->calls, link)
128		if (c->cref == cref->cref && (!c->mine == !cref->flag))
129			return (c);
130	return (NULL);
131}
132struct call *
133uni_find_callx(struct uni *uni, u_int cref, u_int mine)
134{
135	struct call *c;
136
137	TAILQ_FOREACH(c, &uni->calls, link)
138		if (c->cref == cref && !c->mine == !mine)
139			return (c);
140	return (NULL);
141}
142
143/*
144 * Create a new call instance. The type must be set by the caller.
145 */
146struct call *
147uni_create_call(struct uni *uni, u_int cref, u_int mine, uint32_t cookie)
148{
149	struct call *c;
150	struct uniapi_call_created *ind;
151	struct uni_msg *api;
152
153	if ((c = CALL_ALLOC()) == NULL)
154		return (NULL);
155
156	if ((ind = ALLOC_API(struct uniapi_call_created, api)) == NULL) {
157		CALL_FREE(c);
158		return (NULL);
159	}
160	ind->cref.cref = cref;
161	ind->cref.flag = mine;
162
163	c->uni = uni;
164	c->type = CALL_NULL;
165	c->cref = cref;
166	c->mine = mine;
167	c->cstate = CALLST_NULL;
168	TAILQ_INIT(&c->parties);
169
170	TIMER_INIT_CALL(c, t301);
171	TIMER_INIT_CALL(c, t303);
172	TIMER_INIT_CALL(c, t308);
173	TIMER_INIT_CALL(c, t310);
174	TIMER_INIT_CALL(c, t313);
175	TIMER_INIT_CALL(c, t322);
176
177	TAILQ_INSERT_HEAD(&uni->calls, c, link);
178
179	uni->funcs->uni_output(uni, uni->arg, UNIAPI_CALL_CREATED, cookie, api);
180
181	VERBOSE(c->uni, UNI_FAC_CALL, 1, "created call %u/%s",
182	    c->cref, c->mine ? "mine" : "his");
183
184	return (c);
185}
186
187struct call *
188uni_create_new_call(struct uni *uni, uint32_t cookie)
189{
190	struct call *c;
191	uint32_t old = uni->cref_alloc++;
192
193  again:
194	if (uni->cref_alloc == (1 << 23))
195		uni->cref_alloc = 1;
196	if (uni->cref_alloc == old)
197		return (NULL);	/* all crefs exhausted!!! */
198	TAILQ_FOREACH(c, &uni->calls, link)
199		if (c->mine && c->cref == uni->cref_alloc) {
200			uni->cref_alloc++;
201			goto again;
202		}
203	return (uni_create_call(uni, uni->cref_alloc, 1, cookie));
204}
205
206/*
207 * Assume timers are all stopped. Memory is not actually freed unless
208 * the reference count drops to 0.
209 * This function is assumed to remove the call from the parent UNI's
210 * call queue.
211 */
212void
213uni_destroy_call(struct call *c, int really)
214{
215	struct uniapi_call_destroyed *ind;
216	struct uni_msg *api;
217	struct party *p;
218
219	VERBOSE(c->uni, UNI_FAC_CALL, 1, "destroying call %u/%s",
220	    c->cref, c->mine ? "mine" : "his");
221
222	TIMER_DESTROY_CALL(c, t301);
223	TIMER_DESTROY_CALL(c, t303);
224	TIMER_DESTROY_CALL(c, t308);
225	TIMER_DESTROY_CALL(c, t310);
226	TIMER_DESTROY_CALL(c, t313);
227	TIMER_DESTROY_CALL(c, t322);
228	TAILQ_REMOVE(&c->uni->calls, c, link);
229
230	uni_delsig(c->uni, SIG_CALL, c, NULL);
231
232	while ((p = TAILQ_FIRST(&c->parties)) != NULL) {
233		TAILQ_REMOVE(&c->parties, p, link);
234		uni_destroy_party(p, really);
235	}
236
237	if (!really) {
238		ind = ALLOC_API(struct uniapi_call_destroyed, api);
239		if (ind != NULL) {
240			ind->cref.cref = c->cref;
241			ind->cref.flag = c->mine;
242
243			uni_enq_coord(c->uni, SIGO_CALL_DESTROYED, 0, api);
244		}
245
246		uni_enq_call(c, SIGC_CALL_DELETE, 0, NULL, NULL);
247		return;
248	}
249
250	CALL_FREE(c);
251}
252
253static void
254allocate_epref(struct call *c, struct uni_ie_epref *epref)
255{
256	struct party *p;
257	uint32_t old = c->epref_alloc++;
258
259  again:
260	if (c->epref_alloc == (1 << 15))
261		c->epref_alloc = 0;
262	if (c->epref_alloc == old)
263		return;		/* all crefs exhausted!!! */
264	TAILQ_FOREACH(p, &c->parties, link)
265		if (p->epref == c->epref_alloc) {
266			c->epref_alloc++;
267			goto again;
268		}
269	IE_SETPRESENT(*epref);
270	epref->flag = 0;
271	epref->epref = c->epref_alloc;
272
273	epref->h.coding = UNI_CODING_ITU;
274	epref->h.act = UNI_IEACT_DEFAULT;
275}
276
277static void
278reset_all_timers(struct call *c)
279{
280	TIMER_STOP_CALL(c, t301);
281	TIMER_STOP_CALL(c, t303);
282	TIMER_STOP_CALL(c, t308);
283	TIMER_STOP_CALL(c, t310);
284	TIMER_STOP_CALL(c, t313);
285	TIMER_STOP_CALL(c, t322);
286}
287
288/*
289 * Initiate call clearing because of a problem. This is label D in
290 * the SDLs and is called from many places.
291 * The call must have constructed the cause IE in struct call.
292 *
293 * Q.2971:Call-Control-U 27/39
294 * Q.2971:Call-Control-N 28/39
295 *
296 * Memory problems are handled differently here: we simply ignore them
297 * by not sending messages or user indications. Because of T308 we
298 * may be lucky to send the message in a second run.
299 *
300 * It is assumed, that the cause for the release is constructed by
301 * the calling function in uni->cause.
302 */
303static void
304clear_callD(struct call *c)
305{
306	struct uni_msg *api;
307	struct uniapi_release_indication *ind;
308	struct party *p;
309	struct uni_all *rel;
310
311	/*
312	 * Send indication to API
313	 */
314	if ((ind = ALLOC_API(struct uniapi_release_indication, api)) != NULL) {
315		ind->release.hdr.cref.cref = c->cref;
316		ind->release.hdr.cref.flag = c->mine;
317		ind->release.hdr.act = UNI_MSGACT_DEFAULT;
318		ind->release.cause[0] = c->uni->cause;
319
320		c->uni->funcs->uni_output(c->uni, c->uni->arg,
321		    UNIAPI_RELEASE_indication, 0, api);
322	}
323
324	reset_all_timers(c);
325
326	if (c->type == CALL_LEAF || c->type == CALL_ROOT) {
327		TAILQ_FOREACH(p, &c->parties, link) {
328			uni_enq_party(p, SIGP_RELEASE_request, 0, NULL, NULL);
329		}
330	}
331
332	memset(&c->msg_release, 0, sizeof(c->msg_release));
333	c->msg_release.cause[0] = c->uni->cause;
334
335	if ((rel = UNI_ALLOC()) != NULL) {
336		rel->u.release = c->msg_release;
337		MK_MSG_ORIG(rel, UNI_RELEASE, c->cref, !c->mine);
338		(void)uni_send_output(rel, c->uni);
339		UNI_FREE(rel);
340	}
341
342	TIMER_START_CALL(c, t308, c->uni->timer308);
343	c->cnt308 = 0;
344
345	if (c->uni->proto == UNIPROTO_UNI40N)
346		set_call_state(c, CALLST_N12);
347	else
348		set_call_state(c, CALLST_U11);
349}
350
351
352/**********************************************************************/
353/*
354 * SETUP message in state NULL
355 *
356 * Q.2971:Call-Control-U 4/39
357 * Q.2971:Call-Control-N 4/39
358 */
359static void
360un0_setup(struct call *c, struct uni_msg *m, struct uni_all *u,
361    enum call_state new_state)
362{
363	struct uni_all *resp;
364	struct party *p;
365	struct uniapi_setup_indication *ind;
366	struct uni_msg *api;
367	enum verify v;
368
369	if ((ind = ALLOC_API(struct uniapi_setup_indication, api)) == NULL) {
370  clear:
371		uni_destroy_call(c, 0);
372		uni_msg_destroy(m);
373		UNI_FREE(u);
374		return;
375	}
376
377	/*
378	 * Analyze message
379	 */
380	(void)uni_decode_body(m, u, &c->uni->cx);
381	MANDATE_IE(c->uni, u->u.setup.bearer, UNI_IE_BEARER);
382	MANDATE_IE(c->uni, u->u.setup.traffic, UNI_IE_TRAFFIC);
383	MANDATE_IE(c->uni, u->u.setup.called, UNI_IE_CALLED);
384
385	/*
386	 * UNI4.0: 9.1.1.2 Notes 2/3
387	 */
388	if (!IE_ISPRESENT(u->u.setup.qos))
389		MANDATE_IE(c->uni, u->u.setup.exqos, UNI_IE_EXQOS);
390	if (!IE_ISPRESENT(u->u.setup.exqos))
391		MANDATE_IE(c->uni, u->u.setup.qos, UNI_IE_QOS);
392
393	/*
394	 * Q.2971
395	 */
396	if (IE_ISGOOD(u->u.setup.bearer) &&
397	    u->u.setup.bearer.cfg == UNI_BEARER_MP) {
398		if (IE_ISGOOD(u->u.setup.epref) &&
399		   u->u.setup.epref.flag == 1) {
400			IE_SETERROR(u->u.setup.epref);
401			(void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF,
402			    u->u.setup.epref.h.act, UNI_IERR_BAD);
403		}
404		uni_mandate_epref(c->uni, &u->u.setup.epref);
405	}
406
407	v = uni_verify(c->uni, u->u.hdr.act);
408	switch (v) {
409
410	  case VFY_RAI:
411		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
412		    UNI_CALLSTATE_U0, NULL, 0);
413		/* FALLTHRU */
414	  case VFY_I:
415		uni_msg_destroy(api);
416		goto clear;
417
418	  case VFY_RAIM:
419	  case VFY_CLR:
420		if ((resp = UNI_ALLOC()) != NULL) {
421			MK_MSG_RESP(resp, UNI_RELEASE_COMPL, &u->u.hdr.cref);
422			uni_vfy_collect_ies(c->uni);
423			resp->u.release_compl.cause[0] = c->uni->cause;
424			uni_send_output(resp, c->uni);
425			UNI_FREE(resp);
426		}
427		uni_msg_destroy(api);
428		goto clear;
429
430	  case VFY_RAP:
431	  case VFY_RAPU:
432		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
433		    map_callstate(new_state), NULL, 0);
434		/* FALLTHRU */
435	  case VFY_OK:
436		break;
437	}
438
439	if (u->u.setup.bearer.cfg == UNI_BEARER_P2P) {
440		c->type = CALL_P2P;
441
442	} else {
443		c->type = CALL_LEAF;
444		if ((p = uni_create_party(c, &u->u.setup.epref)) == NULL) {
445			uni_msg_destroy(api);
446			goto clear;
447		}
448		uni_enq_party(p, SIGP_SETUP, 0, NULL, NULL);
449	}
450
451	ind->setup.hdr = u->u.hdr;
452	copy_msg_setup(&u->u.setup, &ind->setup);
453	c->uni->funcs->uni_output(c->uni, c->uni->arg,
454	    UNIAPI_SETUP_indication, 0, api);
455
456	uni_msg_destroy(m);
457	UNI_FREE(u);
458
459	set_call_state(c, new_state);
460}
461
462/*
463 * Setup.request from user
464 *
465 * Q.2971:Call-Control-U 4/39 (U0)
466 * Q.2971:Call-Control-N 4/39 (N0)
467 */
468static void
469un0_setup_request(struct call *c, struct uni_msg *m, uint32_t cookie,
470    enum call_state new_state)
471{
472	struct uniapi_setup_request *arg =
473	    uni_msg_rptr(m, struct uniapi_setup_request *);
474	struct uni_setup *setup = &arg->setup;
475	struct uni_all *out;
476	struct party *p;
477
478	if (!IE_ISGOOD(setup->bearer)) {
479		uni_msg_destroy(m);
480		uniapi_call_error(c, UNIAPI_ERROR_MISSING_IE, cookie);
481		uni_destroy_call(c, 0);
482		return;
483	}
484	if ((out = UNI_ALLOC()) == NULL) {
485		uni_msg_destroy(m);
486		uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
487		uni_destroy_call(c, 0);
488		return;
489	}
490
491	c->msg_setup = *setup;
492
493	if (IE_ISGOOD(setup->connid))
494		c->connid = setup->connid;
495
496	if (setup->bearer.cfg == UNI_BEARER_P2P) {
497		c->type = CALL_P2P;
498	} else {
499		c->type = CALL_ROOT;
500
501		/*
502		 * If the user didn't specify a endpoint reference,
503		 * use 0. Use IE_IGNORE accoring to Appendix II Q.2971
504		 */
505		if (!IE_ISPRESENT(c->msg_setup.epref)) {
506			MK_IE_EPREF(c->msg_setup.epref, 0, 0);
507			if (c->uni->proto == UNIPROTO_UNI40N)
508				c->msg_setup.epref.h.act = UNI_IEACT_IGNORE;
509
510		} else if (!IE_ISGOOD(c->msg_setup.epref)) {
511			uni_msg_destroy(m);
512			uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
513			uni_destroy_call(c, 0);
514			return;
515		}
516		if ((p = uni_create_partyx(c, 0, 1, cookie)) == NULL) {
517			uni_msg_destroy(m);
518			uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
519			uni_destroy_call(c, 0);
520			return;
521		}
522		uni_enq_party(p, SIGP_SETUP_request, cookie, NULL, NULL);
523	}
524
525	uni_msg_destroy(m);
526
527	out->u.setup = c->msg_setup;
528	MK_MSG_ORIG(out, UNI_SETUP, c->cref, !c->mine);
529	(void)uni_send_output(out, c->uni);
530	UNI_FREE(out);
531
532	TIMER_START_CALL(c, t303, c->uni->timer303);
533	c->cnt303 = 0;
534
535	set_call_state(c, new_state);
536
537	uniapi_call_error(c, UNIAPI_OK, cookie);
538}
539
540/*
541 * CALL PROCEEDING message
542 *
543 * Q.2971:Call-Control-U 6/39 (in U1)
544 * Q.2971:Call-Control-N 11/39 (in N6)
545 */
546static void
547u1n6_call_proc(struct call *c, struct uni_msg *m, struct uni_all *u,
548    enum call_state new_state)
549{
550	struct uni_call_proc *cp = &u->u.call_proc;
551	struct uniapi_proceeding_indication *ind;
552	struct uni_msg *api;
553
554	ind = ALLOC_API(struct uniapi_proceeding_indication, api);
555	if (ind == NULL) {
556  ignore:
557		uni_msg_destroy(m);
558		UNI_FREE(u);
559		return;
560	}
561	/*
562	 * Analyze message
563	 */
564	(void)uni_decode_body(m, u, &c->uni->cx);
565	if (!IE_ISPRESENT(c->connid) && !IE_ISGOOD(cp->connid))
566		uni_mandate_ie(c->uni, UNI_IE_CONNID);
567
568	/*
569	 * Q.2971: L3MU_01_03 requests us to ignore the message if
570	 * the EPREF is missing.
571	 */
572	if (c->msg_setup.bearer.cfg == UNI_BEARER_MP &&
573	    IE_ISPRESENT(c->msg_setup.epref)) {
574		if (!IE_ISPRESENT(cp->epref))
575			uni_mandate_ie(c->uni, UNI_IE_EPREF);				\
576
577		else if (IE_ISGOOD(cp->epref) &&
578		    (cp->epref.flag != 1 ||
579		     cp->epref.epref != c->msg_setup.epref.epref)) {
580			IE_SETERROR(cp->epref);
581			(void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF,
582			    cp->epref.h.act, UNI_IERR_BAD);
583		}
584	}
585
586	switch (uni_verify(c->uni, u->u.hdr.act)) {
587
588	  case VFY_CLR:
589		uni_vfy_collect_ies(c->uni);
590		clear_callD(c);
591		/* FALLTHRU */
592	  case VFY_I:
593		uni_msg_destroy(api);
594		goto ignore;
595
596	  case VFY_RAIM:
597	  case VFY_RAI:
598	  report:
599		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
600		    map_callstate(c->cstate), NULL, 0);
601		uni_msg_destroy(api);
602		goto ignore;
603
604	  case VFY_RAP:
605	  case VFY_RAPU:
606		if (c->type == CALL_ROOT && !IE_ISGOOD(cp->epref))
607			goto report;
608		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
609		    map_callstate(new_state), NULL, 0);
610		/* FALLTHRU */
611	  case VFY_OK:
612		break;
613	}
614
615	TIMER_STOP_CALL(c, t303);
616
617	if (IE_ISGOOD(cp->connid))
618		c->connid = cp->connid;
619
620	ind->call_proc.hdr = u->u.hdr;
621	copy_msg_call_proc(cp, &ind->call_proc);
622	c->uni->funcs->uni_output(c->uni, c->uni->arg,
623	    UNIAPI_PROCEEDING_indication, 0, api);
624
625	TIMER_START_CALL(c, t310, c->uni->timer310);
626
627	uni_msg_destroy(m);
628	UNI_FREE(u);
629
630	set_call_state(c, new_state);
631}
632
633/*
634 * T303 tick.
635 *
636 * Q.2971:Call-Control-U 6/39
637 * Q.2971:Call-Control-N 11/39
638 */
639static void
640u1n6_t303(struct call *c)
641{
642	struct uni_all *msg;
643	struct uniapi_release_confirm *conf;
644	struct uni_msg *api;
645
646	VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T303 tick %d",
647	    c->cref, c->mine ? "mine" : "his", c->cnt303 + 1);
648
649	if (++c->cnt303 < c->uni->init303) {
650		if ((msg = UNI_ALLOC()) != NULL) {
651			msg->u.setup = c->msg_setup;
652			MK_MSG_ORIG(msg, UNI_SETUP, c->cref, !c->mine);
653			(void)uni_send_output(msg, c->uni);
654			UNI_FREE(msg);
655		}
656		TIMER_START_CALL(c, t303, c->uni->timer303);
657		return;
658	}
659
660	/*
661	 * Send indication to API
662	 */
663	if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) != NULL) {
664		conf->release.hdr.cref.cref = c->cref;
665		conf->release.hdr.cref.flag = c->mine;
666		conf->release.hdr.act = UNI_MSGACT_DEFAULT;
667		MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER,
668		    UNI_CAUSE_NO_RESPONSE);
669
670		c->uni->funcs->uni_output(c->uni, c->uni->arg,
671		    UNIAPI_RELEASE_confirm, 0, api);
672	}
673
674	/*
675	 * send to party (there may be only one)
676	 */
677	if (c->type == CALL_ROOT && !TAILQ_EMPTY(&c->parties)) {
678		uni_enq_party(TAILQ_FIRST(&c->parties),
679		    SIGP_RELEASE_confirm, 0, NULL, NULL);
680	}
681	uni_destroy_call(c, 0);
682}
683
684/*
685 * T310 (Call Proceeding) timer tick.
686 *
687 * Q.2971:Call-Control-U 7/39
688 * Q.2971:Call-Control-N 17/39
689 */
690static void
691u3n9_t310(struct call *c)
692{
693	VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T310 tick",
694	    c->cref, c->mine ? "mine" : "his");
695
696	MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_NO_RESPONSE);
697	clear_callD(c);
698}
699
700/*
701 * T301 (Alerting) timer tick.
702 *
703 * Q.2971:Call-Control-U Missing
704 * Q.2971:Call-Control-N 14/39
705 */
706static void
707u4n7_t301(struct call *c)
708{
709	VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T301 tick",
710	    c->cref, c->mine ? "mine" : "his");
711
712	MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_NO_RESP_ALERT);
713	clear_callD(c);
714}
715
716/*
717 * ALERTING received
718 *
719 * Q.2971:Call-Control-U 37/39 (U1)
720 * Q.2971:Call-Control-U 7/39 (U3)
721 * Q.2971:Call-Control-N 9/39 (N6)
722 * Q.2971:Call-Control-N 17/39 (N9)
723 *
724 * There are two errors in the user side SDL Annex A:
725 *
726 *   - the resetted timers are swapped (T310 and T303)
727 *
728 *   - for U1 we should go to C12, not C3 to start T301.
729 */
730static void
731unx_alerting(struct call *c, struct uni_msg *m, struct uni_all *u,
732    enum call_state new_state)
733{
734	struct uni_alerting *al = &u->u.alerting;
735	struct uniapi_alerting_indication *ind;
736	struct uni_msg *api;
737
738	ind = ALLOC_API(struct uniapi_alerting_indication, api);
739	if (ind == NULL) {
740  ignore:
741		uni_msg_destroy(m);
742		UNI_FREE(u);
743		return;
744	}
745
746	/*
747	 * Analyze message
748	 */
749	(void)uni_decode_body(m, u, &c->uni->cx);
750	if (!IE_ISPRESENT(c->connid) && !IE_ISGOOD(al->connid))
751		uni_mandate_ie(c->uni, UNI_IE_CONNID);
752
753	/*
754	 * Q.2971: L3MU_01_04 requests us to ignore the message if the
755	 * EPREF is missing.
756	 */
757	if (c->msg_setup.bearer.cfg == UNI_BEARER_MP &&
758	    IE_ISPRESENT(c->msg_setup.epref)) {
759		if (!IE_ISPRESENT(al->epref))
760			uni_mandate_ie(c->uni, UNI_IE_EPREF);				\
761
762		else if (IE_ISGOOD(al->epref) &&
763		    (al->epref.flag != 1 ||
764		     al->epref.epref != c->msg_setup.epref.epref)) {
765			IE_SETERROR(al->epref);
766			(void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF,
767			    al->epref.h.act, UNI_IERR_BAD);
768		}
769	}
770
771	switch (uni_verify(c->uni, u->u.hdr.act)) {
772
773	  case VFY_CLR:
774		uni_vfy_collect_ies(c->uni);
775		clear_callD(c);
776	  case VFY_I:
777		uni_msg_destroy(api);
778	  	goto ignore;
779
780	  case VFY_RAIM:
781	  case VFY_RAI:
782	  report:
783		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
784		    map_callstate(c->cstate), NULL, 0);
785		uni_msg_destroy(api);
786	  	goto ignore;
787
788	  case VFY_RAP:
789	  case VFY_RAPU:
790		if (c->type == CALL_ROOT && !IE_ISGOOD(al->epref))
791			goto report;
792		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
793		    map_callstate(c->cstate), NULL, 0);
794	  case VFY_OK:
795		break;
796	}
797
798	if (c->cstate == CALLST_U1 || c->cstate == CALLST_N6)
799		TIMER_STOP_CALL(c, t303);
800	else if (c->cstate == CALLST_U3 || c->cstate == CALLST_N9)
801		TIMER_STOP_CALL(c, t310);
802
803	if (IE_ISGOOD(al->connid))
804		c->connid = al->connid;
805
806	ind->alerting.hdr = u->u.hdr;
807	copy_msg_alerting(al, &ind->alerting);
808
809	if (c->type == CALL_LEAF || c->type == CALL_ROOT) {
810		uni_enq_party(TAILQ_FIRST(&c->parties), SIGP_ALERTING,
811		    0, NULL, NULL);
812		c->uni->funcs->uni_output(c->uni, c->uni->arg,
813		    UNIAPI_ALERTING_indication, 0, api);
814	} else {
815		c->uni->funcs->uni_output(c->uni, c->uni->arg,
816		    UNIAPI_ALERTING_indication, 0, api);
817		TIMER_START_CALL(c, t301, c->uni->timer301);
818	}
819	UNI_FREE(u);
820	uni_msg_destroy(m);
821
822	set_call_state(c, new_state);
823}
824
825/*
826 * Proceeding.request from API
827 *
828 * Q.2971:Call-Control-U 12/39 (U6)
829 * Q.2971:Call-Control-N 6/39 (N1)
830 */
831static void
832u6n1_proceeding_request(struct call *c, struct uni_msg *m, uint32_t cookie,
833    enum call_state new_state)
834{
835	struct uni_all *msg;
836	struct uniapi_proceeding_request *arg =
837	    uni_msg_rptr(m, struct uniapi_proceeding_request *);
838
839	if ((msg = UNI_ALLOC()) == NULL) {
840		uni_msg_destroy(m);
841		uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
842		return;
843	}
844
845	if (IE_ISGOOD(arg->call_proc.connid))
846		c->connid = arg->call_proc.connid;
847
848	msg->u.call_proc = arg->call_proc;
849	MK_MSG_ORIG(msg, UNI_CALL_PROC, c->cref, !c->mine);
850	(void)uni_send_output(msg, c->uni);
851	UNI_FREE(msg);
852
853	set_call_state(c, new_state);
854
855	uni_msg_destroy(m);
856
857	uniapi_call_error(c, UNIAPI_OK, cookie);
858}
859
860/*
861 * Alerting.request from API
862 *
863 * Q.2971:Call-Control-U 13/39 (U6)
864 * Q.2971:Call-Control-U 17/39 (U9)
865 * Q.2971:Call-Control-N 38/39 (N1)
866 * Q.2971:Call-Control-N 7/39  (N3)
867 */
868static void
869unx_alerting_request(struct call *c, struct uni_msg *m, uint32_t cookie,
870    enum call_state new_state)
871{
872	struct uni_all *msg;
873	struct uniapi_alerting_request *arg =
874	    uni_msg_rptr(m, struct uniapi_alerting_request *);
875
876	if ((msg = UNI_ALLOC()) == NULL) {
877		uni_msg_destroy(m);
878		uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
879		return;
880	}
881
882	if (c->type == CALL_ROOT || c->type == CALL_LEAF) {
883		uni_enq_party(TAILQ_FIRST(&c->parties),
884		    SIGP_ALERTING_request, cookie, NULL, NULL);
885	}
886
887	/*
888	 * It's not really clear, what happens, if we send another
889	 * connid in CALL_PROC and ALERTING
890	 */
891	if (!IE_ISGOOD(c->connid) && IE_ISGOOD(arg->alerting.connid))
892		c->connid = arg->alerting.connid;
893
894	msg->u.alerting = arg->alerting;
895	MK_MSG_ORIG(msg, UNI_ALERTING, c->cref, !c->mine);
896	(void)uni_send_output(msg, c->uni);
897	UNI_FREE(msg);
898
899	set_call_state(c, new_state);
900
901	uni_msg_destroy(m);
902
903	uniapi_call_error(c, UNIAPI_OK, cookie);
904}
905
906
907/*
908 * Setup.response from API
909 *
910 * Q.2971:Call-Control-U 13/39	(U6)
911 * Q.2971:Call-Control-U 14/39	(U7)
912 * Q.2971:Call-Control-U 17/39	(U9)
913 * Q.2971:Call-Control-N 39/39  (N1)
914 * Q.2971:Call-Control-N 7/39   (N3)
915 * Q.2971:Call-Control-N 8/39   (N4)
916 */
917static void
918unx_setup_response(struct call *c, struct uni_msg *m, uint32_t cookie,
919    enum call_state new_state)
920{
921	struct uni_all *msg;
922	struct uniapi_setup_response *arg =
923	    uni_msg_rptr(m, struct uniapi_setup_response *);
924	struct party *p;
925
926	if ((msg = UNI_ALLOC()) == NULL) {
927		uni_msg_destroy(m);
928		uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
929		return;
930	}
931
932	if (!IE_ISGOOD(c->connid) && IE_ISGOOD(arg->connect.connid))
933		c->connid = arg->connect.connid;
934
935	if (IE_ISGOOD(arg->connect.epref)) {
936		p = uni_find_partyx(c, arg->connect.epref.epref,
937		    !arg->connect.epref.flag);
938		if (p == NULL) {
939			uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
940			UNI_FREE(msg);
941			uni_msg_destroy(m);
942			return;
943		}
944		/* we need to remember that we have sent the CONNECT from this
945		 * party because the CONNECT ACK must move only this party
946		 * into P7 */
947		p->flags |= PARTY_CONNECT;
948
949	} else if (c->type == CALL_LEAF) {
950		/* XXX don't mandate if only one party */
951		uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
952		UNI_FREE(msg);
953		uni_msg_destroy(m);
954		return;
955	}
956
957	/* inform the parties on the network side */
958	if (c->uni->proto == UNIPROTO_UNI40N && c->type == CALL_LEAF)
959		TAILQ_FOREACH(p, &c->parties, link)
960			uni_enq_party(p, SIGP_SETUP_response, 0, NULL, NULL);
961
962	msg->u.connect = arg->connect;
963	MK_MSG_ORIG(msg, UNI_CONNECT, c->cref, !c->mine);
964	(void)uni_send_output(msg, c->uni);
965	UNI_FREE(msg);
966
967	if (c->uni->proto == UNIPROTO_UNI40U)
968		TIMER_START_CALL(c, t313, c->uni->timer313);
969
970	set_call_state(c, new_state);
971
972	uni_msg_destroy(m);
973
974	uniapi_call_error(c, UNIAPI_OK, cookie);
975}
976
977/*
978 * Setup_complete.request
979 *
980 * Q.2971:Call-Control-N 15/39 (N8)
981 */
982static void
983n8_setup_compl_request(struct call *c, struct uni_msg *m, uint32_t cookie,
984    enum call_state new_state)
985{
986	struct uni_all *msg;
987	struct uniapi_setup_complete_request *arg =
988	    uni_msg_rptr(m, struct uniapi_setup_complete_request *);
989	struct party *p;
990
991	if ((msg = UNI_ALLOC()) == NULL) {
992		uni_msg_destroy(m);
993		uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
994		return;
995	}
996
997	/* inform the parties on the network side */
998	if (c->uni->proto == UNIPROTO_UNI40N &&
999	    (c->type == CALL_LEAF || c->type == CALL_ROOT)) {
1000		TAILQ_FOREACH(p, &c->parties, link)
1001			uni_enq_party(p, SIGP_SETUP_COMPL_request,
1002			    0, NULL, NULL);
1003	}
1004
1005	msg->u.connect_ack = arg->connect_ack;
1006	MK_MSG_ORIG(msg, UNI_CONNECT_ACK, c->cref, !c->mine);
1007	(void)uni_send_output(msg, c->uni);
1008	UNI_FREE(msg);
1009
1010	set_call_state(c, new_state);
1011
1012	uni_msg_destroy(m);
1013
1014	uniapi_call_error(c, UNIAPI_OK, cookie);
1015}
1016
1017/*
1018 * CONNECT message
1019 *
1020 * Q.2971:Call-Control-U 7-8/39  (U3)
1021 * Q.2971:Call-Control-U 11/39   (U4)
1022 * Q.2971:Call-Control-U 37/39   (U1)
1023 * Q.2971:Call-Control-N 9-10/39 (N6)
1024 * Q.2971:Call-Control-N 14/39   (N7)
1025 * Q.2971:Call-Control-N 17/39   (N9)
1026 */
1027static void
1028unx_connect(struct call *c, struct uni_msg *m, struct uni_all *u,
1029    enum call_state new_state)
1030{
1031	struct uni_connect *co = &u->u.connect;
1032	struct uniapi_setup_confirm *conf;
1033	struct uni_msg *api;
1034	struct uni_all *ack;
1035	struct party *p;
1036
1037	conf = ALLOC_API(struct uniapi_setup_confirm, api);
1038	if (conf == NULL) {
1039  ignore:
1040		UNI_FREE(u);
1041		uni_msg_destroy(m);
1042		return;
1043	}
1044	if ((ack = UNI_ALLOC()) == NULL) {
1045		uni_msg_destroy(api);
1046		goto ignore;
1047	}
1048
1049	/*
1050	 * Analyze message
1051	 */
1052	(void)uni_decode_body(m, u, &c->uni->cx);
1053	if (!IE_ISPRESENT(c->connid) && !IE_ISGOOD(co->connid))
1054		uni_mandate_ie(c->uni, UNI_IE_CONNID);
1055
1056	/*
1057	 * Q.2971: L3MU_01_05 requires the epref to be present.
1058	 */
1059	p = NULL;
1060	if (c->msg_setup.bearer.cfg == UNI_BEARER_MP) {
1061		if (IE_ISPRESENT(c->msg_setup.epref)) {
1062			if (!IE_ISPRESENT(co->epref))
1063				uni_mandate_ie(c->uni, UNI_IE_EPREF);				\
1064
1065			if (IE_ISGOOD(co->epref) &&
1066			    co->epref.flag != 1) {
1067				IE_SETERROR(co->epref);
1068				(void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF,
1069				    co->epref.h.act, UNI_IERR_BAD);
1070			}
1071		}
1072
1073		if (IE_ISGOOD(co->epref)) {
1074			p = uni_find_party(c, &co->epref);
1075			if (p == NULL) {
1076				respond_drop_party_ack(c, &co->epref,
1077				    UNI_CAUSE_ENDP_INV);
1078				uni_msg_destroy(api);
1079				UNI_FREE(ack);
1080				goto ignore;
1081			}
1082		}
1083	}
1084
1085	switch (uni_verify(c->uni, u->u.hdr.act)) {
1086
1087	  case VFY_CLR:
1088		uni_vfy_collect_ies(c->uni);
1089		clear_callD(c);
1090		/* FALLTHRU */
1091	  case VFY_I:
1092		uni_msg_destroy(api);
1093		UNI_FREE(ack);
1094	  	goto ignore;
1095
1096	  case VFY_RAIM:
1097	  case VFY_RAI:
1098	  report:
1099		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
1100		    map_callstate(c->cstate), NULL, 0);
1101		uni_msg_destroy(api);
1102		UNI_FREE(ack);
1103	  	goto ignore;
1104
1105	  case VFY_RAP:
1106	  case VFY_RAPU:
1107		if (c->type == CALL_ROOT && !IE_ISGOOD(co->epref))
1108			goto report;
1109		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
1110		    map_callstate(new_state), NULL, 0);
1111		/* FALLTHRU */
1112	  case VFY_OK:
1113		break;
1114	}
1115
1116	if (IE_ISGOOD(co->connid))
1117		c->connid = co->connid;
1118
1119	if (c->cstate == CALLST_U1 || c->cstate == CALLST_N6)
1120		TIMER_STOP_CALL(c, t303);
1121	else if (c->cstate == CALLST_U3 || c->cstate == CALLST_N9)
1122		TIMER_STOP_CALL(c, t310);
1123	else if (c->cstate == CALLST_U4 || c->cstate == CALLST_N7) {
1124		if(c->type == CALL_P2P)
1125			TIMER_STOP_CALL(c, t301);
1126	}
1127
1128	/*
1129	 * This is sent to the party only on the user side and only
1130	 * to the one party in the epref (L3MU_05_03).
1131	 */
1132	if (c->uni->proto == UNIPROTO_UNI40U &&
1133	    (c->type == CALL_LEAF || c->type == CALL_ROOT))
1134		uni_enq_party(p, SIGP_CONNECT, 0, NULL, NULL);
1135
1136	conf->connect.hdr = u->u.hdr;
1137	copy_msg_connect(co, &conf->connect);
1138	c->uni->funcs->uni_output(c->uni, c->uni->arg,
1139	    UNIAPI_SETUP_confirm, 0, api);
1140
1141	if (c->uni->proto == UNIPROTO_UNI40U) {
1142		/* this is left to the application on the network side */
1143		MK_MSG_ORIG(ack, UNI_CONNECT_ACK, c->cref, !c->mine);
1144		(void)uni_send_output(ack, c->uni);
1145		UNI_FREE(ack);
1146	}
1147
1148	UNI_FREE(u);
1149	uni_msg_destroy(m);
1150
1151	set_call_state(c, new_state);
1152}
1153
1154/*
1155 * T313 (Connect) timer tick.
1156 *
1157 * Q.2971:Call-Control-U 15/39
1158 */
1159static void
1160u8_t313(struct call *c)
1161{
1162	VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T313 tick",
1163	    c->cref, c->mine ? "mine" : "his");
1164
1165	MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_RECOVER);
1166	ADD_CAUSE_TIMER(c->uni->cause, "313");
1167	clear_callD(c);
1168}
1169
1170/*
1171 * CONNECT ACKNOWLEDGE message in U8
1172 *
1173 * Q.2971:Call-Control-U 15-16/39
1174 */
1175static void
1176u8_connect_ack(struct call *c, struct uni_msg *m, struct uni_all *u,
1177    enum call_state new_state)
1178{
1179	struct uniapi_setup_complete_indication *ind;
1180	struct uni_msg *api;
1181
1182	ind = ALLOC_API(struct uniapi_setup_complete_indication, api);
1183	if (ind == NULL) {
1184  ignore:
1185		uni_msg_destroy(m);
1186		UNI_FREE(u);
1187		return;
1188	}
1189
1190	/*
1191	 * Analyze message
1192	 */
1193	(void)uni_decode_body(m, u, &c->uni->cx);
1194
1195	switch (uni_verify(c->uni, u->u.hdr.act)) {
1196
1197	  case VFY_CLR:
1198		uni_vfy_collect_ies(c->uni);
1199		clear_callD(c);
1200		/* FALLTHRU */
1201	  case VFY_I:
1202		uni_msg_destroy(api);
1203	  	goto ignore;
1204
1205	  case VFY_RAIM:
1206	  case VFY_RAI:
1207		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
1208		    map_callstate(c->cstate), NULL, 0);
1209		uni_msg_destroy(api);
1210	  	goto ignore;
1211
1212	  case VFY_RAP:
1213	  case VFY_RAPU:
1214		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
1215		    map_callstate(new_state), NULL, 0);
1216		/* FALLTHRU */
1217	  case VFY_OK:
1218		break;
1219	}
1220
1221	TIMER_STOP_CALL(c, t313);
1222
1223	if (c->type == CALL_LEAF) {
1224		struct party *p;
1225
1226		TAILQ_FOREACH(p, &c->parties, link) {
1227			if (p->flags & PARTY_CONNECT) {
1228				uni_enq_party(p, SIGP_CONNECT_ACK,
1229				    0, NULL, NULL);
1230				break;
1231			}
1232		}
1233	}
1234
1235	ind->connect_ack.hdr = u->u.hdr;
1236	copy_msg_connect_ack(&u->u.connect_ack, &ind->connect_ack);
1237	c->uni->funcs->uni_output(c->uni, c->uni->arg,
1238	    UNIAPI_SETUP_COMPLETE_indication, 0, api);
1239
1240	UNI_FREE(u);
1241	uni_msg_destroy(m);
1242
1243	set_call_state(c, new_state);
1244}
1245
1246/*
1247 * CONNECT ACKNOWLEDGE message in N10
1248 *
1249 * Q.2971:Call-Control-N 18/39
1250 */
1251static void
1252n10_connect_ack(struct call *c, struct uni_msg *m, struct uni_all *u)
1253{
1254	/*
1255	 * Analyze message
1256	 */
1257	(void)uni_decode_body(m, u, &c->uni->cx);
1258
1259	switch (uni_verify(c->uni, u->u.hdr.act)) {
1260
1261	  case VFY_CLR:
1262		uni_vfy_collect_ies(c->uni);
1263		clear_callD(c);
1264		/* FALLTHRU */
1265	  case VFY_I:
1266		uni_msg_destroy(m);
1267		UNI_FREE(u);
1268	  	return;
1269
1270	  case VFY_RAIM:
1271	  case VFY_RAI:
1272	  case VFY_RAP:
1273	  case VFY_RAPU:
1274		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
1275		    map_callstate(c->cstate), NULL, 0);
1276		/* FALLTHRU */
1277	  case VFY_OK:
1278		uni_msg_destroy(m);
1279		UNI_FREE(u);
1280	  	return;
1281	}
1282}
1283
1284/*
1285 * Release.response in U6 or U12.
1286 *
1287 * Q.2971:Call-Control-U 12/39 (U6)
1288 * Q.2971:Call-Control-U 30/39 (U12)
1289 * Q.2971:Call-Control-N 6/39  (N1)
1290 * Q.2971:Call-Control-N 29/39 (N11)
1291 */
1292static void
1293unx_release_response(struct call *c, struct uni_msg *m, uint32_t cookie)
1294{
1295	struct party *p;
1296	struct uni_all *msg;
1297	struct uniapi_release_response *arg =
1298	    uni_msg_rptr(m, struct uniapi_release_response *);
1299
1300	if ((msg = UNI_ALLOC()) == NULL) {
1301		uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
1302		uni_msg_destroy(m);
1303		return;
1304	}
1305
1306	if (c->cstate == CALLST_U6 || c->cstate == CALLST_N1) {
1307		if (c->type == CALL_ROOT || c->type == CALL_LEAF) {
1308			TAILQ_FOREACH(p, &c->parties, link)
1309				uni_enq_party(p, SIGP_RELEASE_response,
1310				   cookie, NULL, NULL);
1311		}
1312	}
1313	msg->u.release_compl = arg->release_compl;
1314	MK_MSG_ORIG(msg, UNI_RELEASE_COMPL, c->cref, !c->mine);
1315	(void)uni_send_output(msg, c->uni);
1316	UNI_FREE(msg);
1317
1318	uni_msg_destroy(m);
1319
1320	uniapi_call_error(c, UNIAPI_OK, cookie);
1321
1322	uni_destroy_call(c, 0);
1323}
1324
1325/*
1326 * Got a RELEASE COMPLETE in any state expect U0
1327 *
1328 * Q.2971:Call-Control-U 25/39
1329 * Q.2971:Call-Control-N 26/39
1330 *
1331 * This is also called from the restart processes.
1332 */
1333void
1334uni_release_compl(struct call *c, struct uni_all *u)
1335{
1336	struct uni_msg *api;
1337	struct uniapi_release_confirm *conf;
1338	struct party *p;
1339	u_int i, j;
1340
1341	if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) == NULL)
1342		return;
1343
1344	reset_all_timers(c);
1345	if (c->type == CALL_ROOT || c->type == CALL_LEAF) {
1346		TAILQ_FOREACH(p, &c->parties, link)
1347			uni_enq_party(p, SIGP_RELEASE_COMPL, 0, NULL, NULL);
1348		/* YYY optional call reoffering 10.3.3/10.3.4 */
1349	}
1350	conf->release.hdr = u->u.hdr;
1351
1352	for (i = j = 0; i < 2; i++)
1353		if (IE_ISGOOD(u->u.release_compl.cause[i]))
1354			conf->release.cause[j++] = u->u.release_compl.cause[i];
1355	for (i = j = 0; i < UNI_NUM_IE_GIT; i++)
1356		if (IE_ISGOOD(u->u.release_compl.git[i]))
1357			conf->release.git[j++] = u->u.release_compl.git[i];
1358	if (IE_ISGOOD(u->u.release_compl.uu))
1359		conf->release.uu = u->u.release_compl.uu;
1360	if (IE_ISGOOD(u->u.release_compl.crankback))
1361		conf->release.crankback = u->u.release_compl.crankback;
1362
1363	c->uni->funcs->uni_output(c->uni, c->uni->arg,
1364	    UNIAPI_RELEASE_confirm, 0, api);
1365
1366	uni_destroy_call(c, 0);
1367}
1368static void
1369unx_release_compl(struct call *c, struct uni_msg *m, struct uni_all *u)
1370{
1371
1372	(void)uni_decode_body(m, u, &c->uni->cx);
1373	(void)uni_verify(c->uni, u->u.hdr.act);	/* no point :-) */
1374
1375	uni_release_compl(c, u);
1376
1377	uni_msg_destroy(m);
1378	UNI_FREE(u);
1379}
1380
1381/*
1382 * Got a RELEASE COMPLETE in any state expect U0 and U11
1383 *
1384 * Q.2971:Call-Control-U 25/39
1385 * Q.2971:Call-Control-N 26/39
1386 */
1387static void
1388unx_release(struct call *c, struct uni_msg *m, struct uni_all *u,
1389    enum call_state new_state)
1390{
1391	struct uniapi_release_indication *ind;
1392	struct uni_msg *api;
1393
1394	if ((ind = ALLOC_API(struct uniapi_release_indication, api)) == NULL) {
1395		uni_msg_destroy(m);
1396		UNI_FREE(u);
1397		return;
1398	}
1399
1400	(void)uni_decode_body(m, u, &c->uni->cx);
1401	(void)uni_verify(c->uni, u->u.hdr.act);	/* no point :-) */
1402
1403	reset_all_timers(c);
1404	if (c->type == CALL_ROOT || c->type == CALL_LEAF) {
1405		struct party *p;
1406
1407		TAILQ_FOREACH(p, &c->parties, link)
1408			uni_enq_party(p, SIGP_RELEASE, 0, NULL, NULL);
1409		/* YYY optional call reoffering 10.3.3/10.3.4 */
1410	}
1411	if (c->cstate != new_state) {
1412		/*
1413		 * According to Q.2971 we should send a 2nd
1414		 * Release.indication.
1415		 * According to Q.2931 the recipte of a RELEASE in U12/N11
1416		 * is illegal.
1417		 * According to us make it legal, but don't send a 2nd
1418		 * indication.
1419		 */
1420		ind->release.hdr = u->u.hdr;
1421		copy_msg_release(&u->u.release, &ind->release);
1422
1423		c->uni->funcs->uni_output(c->uni, c->uni->arg,
1424		    UNIAPI_RELEASE_indication, 0, api);
1425	} else
1426		uni_msg_destroy(api);
1427
1428	uni_msg_destroy(m);
1429	UNI_FREE(u);
1430
1431	set_call_state(c, new_state);
1432}
1433
1434/*
1435 * Got RELEASE in U11 or N12
1436 *
1437 * Q.2971:Call-Control-U 28/39
1438 * Q.2971:Call-Control-N 30/39
1439 */
1440static void
1441u11n12_release(struct call *c, struct uni_msg *m, struct uni_all *u)
1442{
1443	struct uniapi_release_confirm *conf;
1444	struct uni_msg *api;
1445
1446	if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) == NULL) {
1447		uni_msg_destroy(m);
1448		UNI_FREE(u);
1449		return;
1450	}
1451
1452	(void)uni_decode_body(m, u, &c->uni->cx);
1453	(void)uni_verify(c->uni, u->u.hdr.act);	/* no point :-) */
1454
1455	TIMER_STOP_CALL(c, t308);
1456
1457	conf->release.hdr = u->u.hdr;
1458	copy_msg_release(&u->u.release, &conf->release);
1459
1460	c->uni->funcs->uni_output(c->uni, c->uni->arg,
1461	    UNIAPI_RELEASE_confirm, 0, api);
1462
1463	uni_msg_destroy(m);
1464	UNI_FREE(u);
1465
1466	uni_destroy_call(c, 0);
1467}
1468
1469/*
1470 * NOTIFY message
1471 *
1472 * Q.2971:Call-Control-U 18/39
1473 * Q.2971:Call-Control-N 19/39
1474 */
1475static void
1476unx_notify(struct call *c, struct uni_msg *m, struct uni_all *u)
1477{
1478	struct uniapi_notify_indication *ind;
1479	struct uni_msg *api;
1480	struct party *p = NULL;
1481
1482	if ((ind = ALLOC_API(struct uniapi_notify_indication, api)) == NULL) {
1483  ignore:
1484		uni_msg_destroy(m);
1485		UNI_FREE(u);
1486		return;
1487	}
1488
1489	/*
1490	 * Analyze message
1491	 */
1492	(void)uni_decode_body(m, u, &c->uni->cx);
1493	MANDATE_IE(c->uni, u->u.notify.notify, UNI_IE_NOTIFY);
1494
1495	if (IE_ISGOOD(u->u.notify.epref)) {
1496		if ((p = uni_find_party(c, &u->u.notify.epref)) == NULL) {
1497			respond_drop_party_ack(c, &u->u.notify.epref,
1498			    UNI_CAUSE_ENDP_INV);
1499			uni_msg_destroy(api);
1500			goto ignore;
1501		}
1502	}
1503
1504	switch (uni_verify(c->uni, u->u.hdr.act)) {
1505
1506	  case VFY_CLR:
1507		uni_msg_destroy(api);
1508		uni_vfy_collect_ies(c->uni);
1509		clear_callD(c);
1510	  	goto ignore;
1511
1512	  case VFY_RAIM:
1513	  case VFY_RAI:
1514		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
1515		    map_callstate(c->cstate), &u->u.notify.epref,
1516		    p ? p->state : 0);
1517		/* FALLTHRU */
1518	  case VFY_I:
1519		uni_msg_destroy(api);
1520	  	goto ignore;
1521
1522	  case VFY_RAP:
1523	  case VFY_RAPU:
1524		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
1525		    map_callstate(c->cstate), &u->u.notify.epref,
1526		    p ? p->state : 0);
1527	  case VFY_OK:
1528		/* FALLTHRU */
1529	  	break;
1530	}
1531
1532	ind->notify.hdr = u->u.hdr;
1533	copy_msg_notify(&u->u.notify, &ind->notify);
1534	c->uni->funcs->uni_output(c->uni, c->uni->arg,
1535	    UNIAPI_NOTIFY_indication, 0, api);
1536
1537	UNI_FREE(u);
1538	uni_msg_destroy(m);
1539}
1540
1541/*
1542 * Notify.request from user
1543 *
1544 * Q.2971:Call-Control-U 18/39
1545 * Q.2971:Call-Control-N 19/39
1546 */
1547static void
1548unx_notify_request(struct call *c, struct uni_msg *m, uint32_t cookie)
1549{
1550	struct uni_all *msg;
1551	struct uniapi_notify_request *arg =
1552	    uni_msg_rptr(m, struct uniapi_notify_request *);
1553
1554	if ((msg = UNI_ALLOC()) == NULL) {
1555		uni_msg_destroy(m);
1556		uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
1557		return;
1558	}
1559
1560	msg->u.notify = arg->notify;
1561	MK_MSG_ORIG(msg, UNI_NOTIFY, c->cref, !c->mine);
1562	(void)uni_send_output(msg, c->uni);
1563	UNI_FREE(msg);
1564
1565	uni_msg_destroy(m);
1566
1567	uniapi_call_error(c, UNIAPI_OK, cookie);
1568}
1569
1570/**********************************************************************/
1571
1572/*
1573 * Release.request from API in any state except U11, U12, N11, N12
1574 *
1575 * Q.2971:Call-Control-U 27/39
1576 * Q.2971:Call-Control-N 28/39
1577 */
1578static void
1579unx_release_request(struct call *c, struct uni_msg *m, uint32_t cookie,
1580    enum call_state new_state)
1581{
1582	struct uni_all *msg;
1583	struct uniapi_release_request *arg =
1584	    uni_msg_rptr(m, struct uniapi_release_request *);
1585	struct party *p;
1586
1587	if ((msg = UNI_ALLOC()) == NULL) {
1588		uni_msg_destroy(m);
1589		uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
1590		return;
1591	}
1592
1593	reset_all_timers(c);
1594
1595	if (c->type == CALL_LEAF || c->type == CALL_ROOT) {
1596		TAILQ_FOREACH(p, &c->parties, link) {
1597			uni_enq_party(p, SIGP_RELEASE_request, cookie,
1598			    NULL, NULL);
1599		}
1600	}
1601
1602	c->msg_release = arg->release;
1603	if (!IE_ISPRESENT(c->msg_release.cause[0]) &&
1604	    !IE_ISPRESENT(c->msg_release.cause[1]))
1605		MK_IE_CAUSE(c->msg_release.cause[0], UNI_CAUSE_LOC_USER,
1606		    UNI_CAUSE_UNSPEC);
1607
1608	msg->u.release = c->msg_release;
1609	MK_MSG_ORIG(msg, UNI_RELEASE, c->cref, !c->mine);
1610	(void)uni_send_output(msg, c->uni);
1611	UNI_FREE(msg);
1612
1613	TIMER_START_CALL(c, t308, c->uni->timer308);
1614	c->cnt308 = 0;
1615
1616	set_call_state(c, new_state);
1617
1618	uni_msg_destroy(m);
1619
1620	uniapi_call_error(c, UNIAPI_OK, cookie);
1621}
1622
1623/*
1624 * Message with unknown EPREF - send a drop party according to 9.5.3.2.3a)
1625 */
1626static void
1627respond_drop_party_ack(struct call *c, struct uni_ie_epref *epref,
1628    u_int cause)
1629{
1630	struct uni_all *msg;
1631
1632	if ((msg = UNI_ALLOC()) == NULL)
1633		return;
1634
1635	MK_MSG_ORIG(msg, UNI_DROP_PARTY_ACK, c->cref, !c->mine);
1636	MK_IE_EPREF(msg->u.drop_party_ack.epref, epref->epref, !epref->flag);
1637	MK_IE_CAUSE(msg->u.drop_party_ack.cause, UNI_CAUSE_LOC_USER, cause);
1638	(void)uni_send_output(msg, c->uni);
1639	UNI_FREE(msg);
1640}
1641
1642/*
1643 * T308 (RELEASE) timer
1644 *
1645 * Q.2971:Call-Control-U 28/39
1646 * Q.2971:Call-Control-N 30/39
1647 */
1648static void
1649u11n12_t308(struct call *c)
1650{
1651	struct uni_all *msg;
1652	struct uni_msg *api;
1653	struct uniapi_release_confirm *conf;
1654
1655	VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T308 tick %d",
1656	    c->cref, c->mine ? "mine" : "his", c->cnt308 + 1);
1657
1658	if (++c->cnt308 < c->uni->init308) {
1659		if ((msg = UNI_ALLOC()) != NULL) {
1660			msg->u.release = c->msg_release;
1661			MK_MSG_ORIG(msg, UNI_RELEASE, c->cref, !c->mine);
1662			if (!IE_ISPRESENT(msg->u.release.cause[1])) {
1663				MK_IE_CAUSE(msg->u.release.cause[1],
1664				    UNI_CAUSE_LOC_USER, UNI_CAUSE_RECOVER);
1665				ADD_CAUSE_TIMER(msg->u.release.cause[1], "308");
1666			}
1667			(void)uni_send_output(msg, c->uni);
1668			UNI_FREE(msg);
1669		}
1670		TIMER_START_CALL(c, t308, c->uni->timer308);
1671		return;
1672	}
1673
1674	/*
1675	 * Send indication to API
1676	 */
1677	if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) != NULL) {
1678		conf->release.hdr.cref.cref = c->cref;
1679		conf->release.hdr.cref.flag = c->mine;
1680		conf->release.hdr.act = UNI_MSGACT_DEFAULT;
1681		MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER,
1682		    UNI_CAUSE_RECOVER);
1683		ADD_CAUSE_TIMER(conf->release.cause[0], "308");
1684
1685		c->uni->funcs->uni_output(c->uni, c->uni->arg,
1686		    UNIAPI_RELEASE_confirm, 0, api);
1687	}
1688
1689	uni_destroy_call(c, 0);
1690}
1691/**********************************************************************/
1692
1693/*
1694 * STATUS in U11/U12
1695 *
1696 * Q.2971:Call-Control-U 29/39 (U11)
1697 * Q.2971:Call-Control-U 30/39 (U12)
1698 * Q.2971:Call-Control-N 29/39 (N11)
1699 * Q.2971:Call-Control-N 31/39 (N12)
1700 */
1701static void
1702un11un12_status(struct call *c, struct uni_msg *m, struct uni_all *u)
1703{
1704	enum call_state ns;
1705	struct uniapi_release_confirm *conf;
1706	struct uni_msg *api;
1707	struct party *p;
1708	struct uniapi_status_indication *stat;
1709
1710	/*
1711	 * Analyze message
1712	 */
1713	(void)uni_decode_body(m, u, &c->uni->cx);
1714	MANDATE_IE(c->uni, u->u.status.callstate, UNI_IE_CALLSTATE);
1715	MANDATE_IE(c->uni, u->u.status.cause, UNI_IE_CAUSE);
1716
1717	ns = c->cstate;
1718	if (IE_ISGOOD(u->u.status.callstate) &&
1719	    u->u.status.callstate.state == UNI_CALLSTATE_U0)
1720		ns = CALLST_NULL;
1721
1722	p = NULL;
1723	if (IE_ISGOOD(u->u.status.epref))
1724		p = uni_find_party(c, &u->u.status.epref);
1725
1726	switch (uni_verify(c->uni, u->u.hdr.act)) {
1727
1728	  case VFY_CLR:
1729		uni_vfy_collect_ies(c->uni);
1730		clear_callD(c);
1731		uni_msg_destroy(m);
1732		UNI_FREE(u);
1733	  	return;
1734
1735	  case VFY_RAIM:
1736	  case VFY_RAI:
1737	  case VFY_RAP:
1738	  case VFY_RAPU:
1739		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
1740		    map_callstate(ns), &u->u.status.epref,
1741		    p ? p->state : UNI_EPSTATE_NULL);
1742	  case VFY_I:
1743	  case VFY_OK:
1744	  	break;
1745	}
1746
1747	if (ns == c->cstate) {
1748		/*
1749		 * Inform API
1750		 */
1751		stat = ALLOC_API(struct uniapi_status_indication, api);
1752		if (stat != NULL) {
1753			stat->cref = u->u.hdr.cref;
1754			stat->my_state = map_callstate(c->cstate);
1755			stat->his_state = u->u.status.callstate;
1756			stat->his_cause = u->u.status.cause;
1757			stat->epref = u->u.status.epref;
1758			stat->epstate = u->u.status.epstate;
1759			stat->my_cause = 0;
1760			c->uni->funcs->uni_output(c->uni, c->uni->arg,
1761			    UNIAPI_STATUS_indication, 0, api);
1762		}
1763
1764		uni_msg_destroy(m);
1765		UNI_FREE(u);
1766
1767		return;
1768	}
1769
1770	uni_msg_destroy(m);
1771	UNI_FREE(u);
1772
1773	/*
1774	 * Send indication to API
1775	 */
1776	if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) != NULL) {
1777		conf->release.hdr.cref.cref = c->cref;
1778		conf->release.hdr.cref.flag = c->mine;
1779		conf->release.hdr.act = UNI_MSGACT_DEFAULT;
1780		MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER,
1781		    UNI_CAUSE_MSG_INCOMP);
1782		ADD_CAUSE_MTYPE(conf->release.cause[0], UNI_STATUS);
1783
1784		c->uni->funcs->uni_output(c->uni, c->uni->arg,
1785		    UNIAPI_RELEASE_confirm, 0, api);
1786	}
1787
1788	uni_destroy_call(c, 0);
1789}
1790
1791static int
1792status_enq_filter(struct sig *sig, void *arg)
1793{
1794	return (sig->type == SIG_CALL &&
1795	    (struct call *)arg == sig->call &&
1796	    sig->sig == SIGC_SEND_STATUS_ENQ);
1797}
1798
1799/*
1800 * STATUS in any state except U0/U11/U12 N0/N11/N12
1801 *
1802 * Q.2971:Call-Control-U 32/39
1803 * Q.2971:Call-Control-N 33/39
1804 */
1805static void
1806unx_status(struct call *c, struct uni_msg *m, struct uni_all *u)
1807{
1808	struct uniapi_status_indication *stat;
1809	struct uniapi_release_confirm *conf;
1810	enum call_state ns;
1811	struct uni_msg *api;
1812	struct party *p;
1813
1814	/*
1815	 * Analyze message
1816	 */
1817	(void)uni_decode_body(m, u, &c->uni->cx);
1818	MANDATE_IE(c->uni, u->u.status.callstate, UNI_IE_CALLSTATE);
1819	MANDATE_IE(c->uni, u->u.status.cause, UNI_IE_CAUSE);
1820
1821	ns = c->cstate;
1822	if (IE_ISGOOD(u->u.status.callstate))
1823		ns = state_compat(c, u->u.status.callstate.state);
1824
1825	p = NULL;
1826	if (IE_ISGOOD(u->u.status.epref)) {
1827		p = uni_find_party(c, &u->u.status.epref);
1828		MANDATE_IE(c->uni, u->u.status.epstate, UNI_IE_EPSTATE);
1829	}
1830
1831	switch (uni_verify(c->uni, u->u.hdr.act)) {
1832
1833	  case VFY_CLR:
1834		uni_vfy_collect_ies(c->uni);
1835		clear_callD(c);
1836		uni_msg_destroy(m);
1837		UNI_FREE(u);
1838	  	return;
1839
1840	  case VFY_RAIM:
1841	  case VFY_RAI:
1842	  case VFY_RAP:
1843	  case VFY_RAPU:
1844		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
1845		    map_callstate(ns), &u->u.notify.epref,
1846		    p ? p->state : UNI_EPSTATE_NULL);
1847		/* FALLTHRU */
1848	  case VFY_I:
1849	  case VFY_OK:
1850	  	break;
1851	}
1852
1853	if (u->u.status.callstate.state == UNI_CALLSTATE_U0) {
1854		/* release_complete */
1855		uni_msg_destroy(m);
1856		UNI_FREE(u);
1857
1858		if (c->type == CALL_LEAF || c->type == CALL_ROOT) {
1859			TAILQ_FOREACH(p, &c->parties, link)
1860				uni_enq_party(p, SIGP_RELEASE_COMPL,
1861				    0, NULL, NULL);
1862		}
1863		/*
1864		 * Send indication to API
1865		 */
1866		conf = ALLOC_API(struct uniapi_release_confirm, api);
1867		if (conf != NULL) {
1868			conf->release.hdr.cref.cref = c->cref;
1869			conf->release.hdr.cref.flag = c->mine;
1870			conf->release.hdr.act = UNI_MSGACT_DEFAULT;
1871			MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER,
1872			    UNI_CAUSE_MSG_INCOMP);
1873			ADD_CAUSE_MTYPE(conf->release.cause[0], UNI_STATUS);
1874
1875			c->uni->funcs->uni_output(c->uni, c->uni->arg,
1876			    UNIAPI_RELEASE_confirm, 0, api);
1877		}
1878		uni_destroy_call(c, 0);
1879		return;
1880	}
1881
1882	if (IE_ISGOOD(u->u.status.cause) &&
1883	    u->u.status.cause.cause == UNI_CAUSE_STATUS) {
1884		c->se_active = 0;
1885		TIMER_STOP_CALL(c, t322);
1886		uni_undel(c->uni, status_enq_filter, c);
1887	}
1888
1889	/*
1890	 * Inform API
1891	 */
1892	if ((stat = ALLOC_API(struct uniapi_status_indication, api)) != NULL) {
1893		stat->cref = u->u.hdr.cref;
1894		stat->my_state = map_callstate(c->cstate);
1895		stat->his_state = u->u.status.callstate;
1896		stat->his_cause = u->u.status.cause;
1897		stat->epref = u->u.status.epref;
1898		stat->epstate = u->u.status.epstate;
1899	}
1900
1901	if (ns == c->cstate) {
1902		/* compatible or recovered */
1903		if (p != NULL)
1904			uni_enq_party(p, SIGP_STATUS, 0, m, u);
1905		else {
1906			if (IE_ISGOOD(u->u.status.epref) &&
1907			    (!IE_ISGOOD(u->u.status.epstate) ||
1908			     u->u.status.epstate.state != UNI_EPSTATE_NULL))
1909				respond_drop_party_ack(c, &u->u.status.epref,
1910				    UNI_CAUSE_MSG_INCOMP);
1911
1912			uni_msg_destroy(m);
1913			UNI_FREE(u);
1914		}
1915		if (stat != NULL) {
1916			stat->my_cause = 0;
1917			c->uni->funcs->uni_output(c->uni, c->uni->arg,
1918			    UNIAPI_STATUS_indication, 0, api);
1919		}
1920
1921		return;
1922	}
1923
1924	/* incompatible */
1925	if (stat != NULL) {
1926		stat->my_cause = UNI_CAUSE_MSG_INCOMP;
1927		c->uni->funcs->uni_output(c->uni, c->uni->arg,
1928		    UNIAPI_STATUS_indication, 0, api);
1929	}
1930
1931	MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_MSG_INCOMP);
1932
1933	uni_msg_destroy(m);
1934	UNI_FREE(u);
1935
1936	clear_callD(c);
1937}
1938
1939/*
1940 * Enquiry peer status
1941 *
1942 * Q.2971:Call-Control-U 31/39
1943 * Q.2971:Call-Control-N 32/39
1944 */
1945static void
1946unx_status_enquiry_request(struct call *c, struct uni_msg *msg, uint32_t cookie)
1947{
1948	struct uniapi_status_enquiry_request *arg =
1949	    uni_msg_rptr(msg, struct uniapi_status_enquiry_request *);
1950	struct party *p;
1951	struct uni_all *stat;
1952
1953	if (c->se_active) {
1954		/* This case is not handled in the SDLs */
1955		uniapi_call_error(c, UNIAPI_ERROR_BUSY, cookie);
1956		uni_msg_destroy(msg);
1957		return;
1958	}
1959	if ((c->type == CALL_ROOT || c->type == CALL_LEAF) &&
1960	    IE_ISGOOD(arg->epref)) {
1961		if ((p = uni_find_partyx(c, arg->epref.epref, !arg->epref.flag))
1962		    == NULL) {
1963			uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
1964			uni_msg_destroy(msg);
1965			return;
1966		}
1967		uni_msg_destroy(msg);
1968		uni_enq_party(p, SIGP_STATUS_ENQUIRY_request, cookie,
1969		    NULL, NULL);
1970		return;
1971	}
1972	if ((stat = UNI_ALLOC()) == NULL) {
1973		uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
1974		uni_msg_destroy(msg);
1975		return;
1976	}
1977	memset(&c->stat_epref, 0, sizeof(c->stat_epref));
1978	MK_MSG_ORIG(stat, UNI_STATUS_ENQ, c->cref, !c->mine);
1979	(void)uni_send_output(stat, c->uni);
1980	UNI_FREE(stat);
1981
1982	TIMER_START_CALL(c, t322, c->uni->timer322);
1983	c->cnt322 = 0;
1984	c->se_active = 1;
1985
1986	uniapi_call_error(c, UNIAPI_OK, cookie);
1987}
1988
1989/*
1990 * T322 tick
1991 *
1992 * Q.2971:Call-Control-U 34/39
1993 * Q.2971:Call-Control-N 35/39
1994 */
1995static void
1996unx_t322(struct call *c)
1997{
1998	struct uni_all *stat;
1999
2000	VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T322 tick %d",
2001	    c->cref, c->mine ? "mine" : "his", c->cnt322 + 1);
2002
2003	if (++c->cnt322 < c->uni->init322) {
2004		if ((stat = UNI_ALLOC()) != NULL) {
2005			MK_MSG_ORIG(stat, UNI_STATUS_ENQ, c->cref, !c->mine);
2006			stat->u.status_enq.epref = c->stat_epref;
2007			(void)uni_send_output(stat, c->uni);
2008			UNI_FREE(stat);
2009		}
2010		TIMER_START_CALL(c, t322, c->uni->timer322);
2011		return;
2012	}
2013	c->se_active = 0;
2014
2015	MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_RECOVER);
2016	ADD_CAUSE_TIMER(c->uni->cause, "322");
2017
2018	clear_callD(c);
2019}
2020
2021/*
2022 * STATUS ENQUIRY message
2023 *
2024 * Q.2971:Call-Control-U 31/39
2025 * Q.2971:Call-Control-N 32/39
2026 */
2027static void
2028unx_status_enq(struct call *c, struct uni_msg *m, struct uni_all *u)
2029{
2030	struct party *p = NULL;
2031	u_int epref, flag;
2032
2033	/*
2034	 * Analyze message
2035	 */
2036	(void)uni_decode_body(m, u, &c->uni->cx);
2037
2038	switch (uni_verify(c->uni, u->u.hdr.act)) {
2039
2040	  case VFY_CLR:
2041		uni_vfy_collect_ies(c->uni);
2042		clear_callD(c);
2043		uni_msg_destroy(m);
2044		UNI_FREE(u);
2045	  	return;
2046
2047	  case VFY_RAIM:
2048	  case VFY_RAI:
2049	  case VFY_RAP:
2050	  case VFY_RAPU:
2051	  case VFY_I:
2052	  case VFY_OK:
2053	  	break;
2054	}
2055
2056	uni_msg_destroy(m);
2057
2058	if ((c->type == CALL_ROOT || c->type == CALL_LEAF) &&
2059	    IE_ISGOOD(u->u.status_enq.epref)) {
2060		p = uni_find_party(c, &u->u.status_enq.epref);
2061
2062		epref = u->u.status_enq.epref.epref;
2063		flag = u->u.status_enq.epref.flag;
2064		memset(u, 0, sizeof(*u));
2065		MK_IE_EPREF(u->u.status.epref, epref, !flag);
2066
2067		if (p != NULL)
2068			MK_IE_EPSTATE(u->u.status.epstate, p->state);
2069		else
2070			MK_IE_EPSTATE(u->u.status.epstate, UNI_EPSTATE_NULL);
2071	} else
2072		memset(u, 0, sizeof(*u));
2073
2074
2075	MK_MSG_ORIG(u, UNI_STATUS, c->cref, !c->mine);
2076	MK_IE_CALLSTATE(u->u.status.callstate, map_callstate(c->cstate));
2077	MK_IE_CAUSE(u->u.status.cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_STATUS);
2078	(void)uni_send_output(u, c->uni);
2079	UNI_FREE(u);
2080}
2081
2082/**********************************************************************/
2083
2084/*
2085 * Link-release.indication from SAAL in state U10 or N10.
2086 *
2087 * Q.2971:Call-Control-U 19/39
2088 * Q.2971:Call-Control-N 20/39
2089 */
2090static void
2091un10_link_release_indication(struct call *c)
2092{
2093	struct party *p;
2094
2095	if (c->type == CALL_LEAF || c->type == CALL_ROOT)
2096		TAILQ_FOREACH(p, &c->parties, link) {
2097			if (p->state != UNI_EPSTATE_ACTIVE)
2098				uni_enq_party(p, SIGP_RELEASE_COMPL,
2099				    0, NULL, NULL);
2100		}
2101
2102	uni_enq_coord(c->uni, SIGO_LINK_ESTABLISH_request, 0, NULL);
2103}
2104
2105/*
2106 * Link-release.indication from SAAL in all state except U10 and N10.
2107 *
2108 * Q.2971:Call-Control-U 36/39
2109 * Q.2971:Call-Control-N 37/39
2110 */
2111static void
2112unx_link_release_indication(struct call *c)
2113{
2114	struct uniapi_release_confirm *conf;
2115	struct uni_msg *api;
2116	struct party *p;
2117
2118	if (c->type == CALL_LEAF || c->type == CALL_ROOT)
2119		TAILQ_FOREACH(p, &c->parties, link)
2120			uni_enq_party(p, SIGP_RELEASE_COMPL, 0, NULL, NULL);
2121
2122	if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) != NULL) {
2123		conf->release.hdr.cref.cref = c->cref;
2124		conf->release.hdr.cref.flag = c->mine;
2125		conf->release.hdr.act = UNI_MSGACT_DEFAULT;
2126		MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER,
2127		    UNI_CAUSE_DST_OOO);
2128
2129		c->uni->funcs->uni_output(c->uni, c->uni->arg,
2130		    UNIAPI_RELEASE_confirm, 0, api);
2131	}
2132
2133	uni_destroy_call(c, 0);
2134}
2135
2136/*
2137 * Failed to establish SAAL link. Can happen only in U10 or N10.
2138 *
2139 * Q.2971:Call-Control-U 19/39
2140 * Q.2971:Call-Control-N 20/39
2141 */
2142static void
2143un10_link_establish_error_indication(struct call *c)
2144{
2145	struct party *p;
2146	struct uni_msg *api;
2147	struct uniapi_release_confirm *conf;
2148
2149	if (c->type == CALL_LEAF || c->type == CALL_ROOT)
2150		TAILQ_FOREACH(p, &c->parties, link)
2151			uni_enq_party(p, SIGP_RELEASE_COMPL, 0, NULL, NULL);
2152
2153	if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) != NULL) {
2154		conf->release.hdr.cref.cref = c->cref;
2155		conf->release.hdr.cref.flag = c->mine;
2156		conf->release.hdr.act = UNI_MSGACT_DEFAULT;
2157		MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER,
2158		    UNI_CAUSE_DST_OOO);
2159
2160		c->uni->funcs->uni_output(c->uni, c->uni->arg,
2161		    UNIAPI_RELEASE_confirm, 0, api);
2162	}
2163
2164	uni_destroy_call(c, 0);
2165}
2166
2167/*
2168 * Issue a STATUS ENQUIRY of we are not busy
2169 *
2170 * Q.2971: Call-Control-U: 34/39
2171 * Q.2971: Call-Control-N: 34/39
2172 */
2173static void
2174call_se(struct call *c)
2175{
2176	struct uni_all *stat;
2177
2178	c->cnt322 = 0;
2179	if (c->se_active)
2180		return;
2181
2182	memset(&c->stat_epref, 0, sizeof(c->stat_epref));
2183	if ((stat = UNI_ALLOC()) != NULL) {
2184		MK_MSG_ORIG(stat, UNI_STATUS_ENQ, c->cref, !c->mine);
2185		(void)uni_send_output(stat, c->uni);
2186		UNI_FREE(stat);
2187	}
2188
2189	TIMER_START_CALL(c, t322, c->uni->timer322);
2190	c->se_active = 1;
2191}
2192
2193/*
2194 * Link-establish.indication in U10
2195 *
2196 * Q.2971:Call-Control-U 19-20/39
2197 * Q.2971:Call-Control-N 20-22/39
2198 */
2199static void
2200un10_link_establish_indication(struct call *c)
2201{
2202	int act = 0;
2203	struct party *p;
2204
2205	if (c->type == CALL_ROOT || c->type == CALL_LEAF) {
2206		TAILQ_FOREACH(p, &c->parties, link)
2207			if (p->state == UNI_EPSTATE_ACTIVE) {
2208				act = 1;
2209				uni_enq_party(p, SIGP_STATUS_ENQUIRY_request,
2210				    0, NULL, NULL);
2211			}
2212		if (act)
2213			return;
2214	}
2215	call_se(c);
2216}
2217
2218/*
2219 * Link-establish.indication in NOT U10/U11/U12 N10/N11/N12
2220 *
2221 * Q.2971:Call-Control-U 36/39
2222 * Q.2971:Call-Control-N 37/39
2223 */
2224static void
2225unx_link_establish_indication(struct call *c)
2226{
2227	call_se(c);
2228}
2229
2230/*
2231 * Link-establish.confirm in U10 or N10
2232 *
2233 * Q.2971:Call-Control-U 19/39
2234 * Q.2971:Call-Control-N 20/39
2235 */
2236static void
2237un10_link_establish_confirm(struct call *c)
2238{
2239	struct party *p;
2240
2241	if (c->type == CALL_ROOT || c->type == CALL_LEAF) {
2242		TAILQ_FOREACH(p, &c->parties, link)
2243			uni_enq_party(p, SIGP_STATUS_ENQUIRY_request,
2244			    0, NULL, NULL);
2245		return;
2246	}
2247
2248	call_se(c);
2249}
2250
2251/*
2252 * STATUS ENQ from party
2253 *
2254 * Q.2971:Call-Control-U 21/39
2255 * Q.2971:Call-Control-U 25/39
2256 */
2257static void
2258unx_send_party_status_enq(struct call *c, struct uni_all *u)
2259{
2260	if (c->se_active) {
2261		uni_delenq_sig(c->uni, SIG_CALL, c, NULL,
2262		    SIGC_SEND_STATUS_ENQ, 0, NULL, u);
2263		return;
2264	}
2265
2266	c->stat_epref = u->u.status_enq.epref;
2267	(void)uni_send_output(u, c->uni);
2268	UNI_FREE(u);
2269
2270	TIMER_START_CALL(c, t322, c->uni->timer322);
2271	c->se_active = 1;
2272}
2273
2274/**********************************************************************/
2275
2276static void
2277make_drop_cause(struct call *c, struct uni_ie_cause *cause)
2278{
2279
2280	if (!IE_ISGOOD(*cause)) {
2281		/* 9.5.7.1 paragraph 2 */
2282		if (IE_ISPRESENT(*cause))
2283			MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER,
2284			    UNI_CAUSE_IE_INV);
2285		else
2286			MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER,
2287			    UNI_CAUSE_MANDAT);
2288		c->uni->cause.u.ie.len = 1;
2289		c->uni->cause.u.ie.ie[0] = UNI_IE_CAUSE;
2290		c->uni->cause.h.present |= UNI_CAUSE_IE_P;
2291
2292	} else if (!IE_ISGOOD(c->uni->cause))
2293		c->uni->cause = *cause;
2294}
2295
2296/*
2297 * Drop-party.indication from Party-Control in any state.
2298 *
2299 * Q.2971:Call-Control-U 23/39
2300 */
2301static void
2302ux_drop_party_indication(struct call *c, struct uni_msg *api)
2303{
2304	struct uniapi_drop_party_indication *drop =
2305	    uni_msg_rptr(api, struct uniapi_drop_party_indication *);
2306
2307	if (uni_party_act_count(c, 2) == 0) {
2308		if (c->cstate != CALLST_U11) {
2309			make_drop_cause(c, &drop->drop.cause);
2310			clear_callD(c);
2311		}
2312		uni_msg_destroy(api);
2313		return;
2314	}
2315	c->uni->funcs->uni_output(c->uni, c->uni->arg,
2316	    UNIAPI_DROP_PARTY_indication, 0, api);
2317}
2318
2319/*
2320 * Drop-party.indication from Party-Control in any state.
2321 *
2322 * Q.2971:Call-Control-N 23/39
2323 */
2324static void
2325nx_drop_party_indication(struct call *c, struct uni_msg *api)
2326{
2327	struct uniapi_drop_party_indication *drop =
2328	    uni_msg_rptr(api, struct uniapi_drop_party_indication *);
2329
2330	if (uni_party_act_count(c, 0) == 0) {
2331		if (uni_party_act_count(c, 1) == 0) {
2332			if (c->cstate != CALLST_U11) {
2333				make_drop_cause(c, &drop->drop.cause);
2334				clear_callD(c);
2335			}
2336			uni_msg_destroy(api);
2337		} else {
2338			c->uni->funcs->uni_output(c->uni, c->uni->arg,
2339			    UNIAPI_DROP_PARTY_indication, 0, api);
2340			set_call_state(c, CALLST_N7);
2341		}
2342	} else {
2343		c->uni->funcs->uni_output(c->uni, c->uni->arg,
2344		    UNIAPI_DROP_PARTY_indication, 0, api);
2345	}
2346}
2347
2348/*
2349 * Drop-party-ack.indication from Party-Control in any state.
2350 *
2351 * Q.2971:Call-Control-U 23/39
2352 */
2353static void
2354ux_drop_party_ack_indication(struct call *c, struct uni_msg *api)
2355{
2356	struct uniapi_drop_party_ack_indication *drop =
2357	    uni_msg_rptr(api, struct uniapi_drop_party_ack_indication *);
2358
2359	if (uni_party_act_count(c, 2) == 0) {
2360		if (c->cstate != CALLST_U11) {
2361			make_drop_cause(c, &drop->drop.cause);
2362			clear_callD(c);
2363		}
2364		uni_msg_destroy(api);
2365		return;
2366	}
2367	c->uni->funcs->uni_output(c->uni, c->uni->arg,
2368	    UNIAPI_DROP_PARTY_ACK_indication, 0, api);
2369}
2370
2371/*
2372 * Drop-party-ack.indication from Party-Control in any state.
2373 *
2374 * Q.2971:Call-Control-N 23/39
2375 */
2376static void
2377nx_drop_party_ack_indication(struct call *c, struct uni_msg *api)
2378{
2379	struct uniapi_drop_party_ack_indication *drop =
2380	    uni_msg_rptr(api, struct uniapi_drop_party_ack_indication *);
2381
2382	if (uni_party_act_count(c, 0) == 0) {
2383		if (uni_party_act_count(c, 1) == 0) {
2384			if (c->cstate != CALLST_U11) {
2385				make_drop_cause(c, &drop->drop.cause);
2386				clear_callD(c);
2387			}
2388			uni_msg_destroy(api);
2389		} else {
2390			c->uni->funcs->uni_output(c->uni, c->uni->arg,
2391			    UNIAPI_DROP_PARTY_ACK_indication, 0, api);
2392			set_call_state(c, CALLST_N7);
2393		}
2394	} else {
2395		c->uni->funcs->uni_output(c->uni, c->uni->arg,
2396		    UNIAPI_DROP_PARTY_ACK_indication, 0, api);
2397	}
2398}
2399
2400/*
2401 * Add-party-rej.indication from Party-Control in any state.
2402 *
2403 * Q.2971:Call-Control-U 23/39
2404 */
2405static void
2406ux_add_party_rej_indication(struct call *c, struct uni_msg *api)
2407{
2408	struct uniapi_add_party_rej_indication *rej =
2409	    uni_msg_rptr(api, struct uniapi_add_party_rej_indication *);
2410
2411	if (uni_party_act_count(c, 2) == 0) {
2412		if (c->cstate != CALLST_U11) {
2413			make_drop_cause(c, &rej->rej.cause);
2414			clear_callD(c);
2415		}
2416		uni_msg_destroy(api);
2417		return;
2418	}
2419	c->uni->funcs->uni_output(c->uni, c->uni->arg,
2420	    UNIAPI_ADD_PARTY_REJ_indication, 0, api);
2421}
2422
2423/*
2424 * Add-party-rej.indication from Party-Control in any state.
2425 *
2426 * Q.2971:Call-Control-N 23/39
2427 */
2428static void
2429nx_add_party_rej_indication(struct call *c, struct uni_msg *api)
2430{
2431	struct uniapi_add_party_rej_indication *rej =
2432	    uni_msg_rptr(api, struct uniapi_add_party_rej_indication *);
2433
2434	if (uni_party_act_count(c, 0) == 0) {
2435		if (uni_party_act_count(c, 1) == 0) {
2436			if (c->cstate != CALLST_U11) {
2437				make_drop_cause(c, &rej->rej.cause);
2438				clear_callD(c);
2439			}
2440			uni_msg_destroy(api);
2441		} else {
2442			c->uni->funcs->uni_output(c->uni, c->uni->arg,
2443			    UNIAPI_ADD_PARTY_REJ_indication, 0, api);
2444			set_call_state(c, CALLST_N7);
2445		}
2446	} else {
2447		c->uni->funcs->uni_output(c->uni, c->uni->arg,
2448		    UNIAPI_ADD_PARTY_REJ_indication, 0, api);
2449	}
2450}
2451
2452/*
2453 * Add-party.request from API in U4 or U10
2454 *
2455 * Q.2971:Call-Control-U 9-10/39 (U4)
2456 * Q.2971:Call-Control-U 21/39 (U10)
2457 * Q.2971:Call-Control-N 12/39 (N7)
2458 * Q.2971:Call-Control-N 22/39 (N10)
2459 */
2460static void
2461unx_add_party_request(struct call *c, struct uni_msg *msg, uint32_t cookie)
2462{
2463	struct uniapi_add_party_request *add =
2464	    uni_msg_rptr(msg, struct uniapi_add_party_request *);
2465	struct party *p;
2466
2467	if (IE_ISGOOD(add->add.epref)) {
2468		if (add->add.epref.flag != 0) {
2469			uni_msg_destroy(msg);
2470			uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2471			return;
2472		}
2473		p = uni_find_partyx(c, add->add.epref.epref, 1);
2474		if (p != NULL) {
2475			uni_msg_destroy(msg);
2476			uniapi_call_error(c, UNIAPI_ERROR_EPREF_INUSE, cookie);
2477			return;
2478		}
2479	} else if (!IE_ISPRESENT(add->add.epref)) {
2480		allocate_epref(c, &add->add.epref);
2481		if (!IE_ISPRESENT(add->add.epref)) {
2482			uni_msg_destroy(msg);
2483			uniapi_call_error(c, UNIAPI_ERROR_EPREF_INUSE, cookie);
2484			return;
2485		}
2486	} else {
2487		uni_msg_destroy(msg);
2488		uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2489		return;
2490	}
2491
2492	if ((p = uni_create_partyx(c, add->add.epref.epref, 1, cookie)) == NULL) {
2493		uni_msg_destroy(msg);
2494		uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
2495		return;
2496	}
2497	uni_enq_party(p, SIGP_ADD_PARTY_request, cookie, msg, NULL);
2498}
2499
2500/*
2501 * Add-party-ack.request from API in U10/N10
2502 *
2503 * Q.2971:Call-Control-U 21/39
2504 * Q.2971:Call-Control-N 22/39
2505 */
2506static void
2507un10_add_party_ack_request(struct call *c, struct uni_msg *msg, uint32_t cookie)
2508{
2509	struct uniapi_add_party_ack_request *ack =
2510	    uni_msg_rptr(msg, struct uniapi_add_party_ack_request *);
2511	struct party *p;
2512
2513	if (!IE_ISGOOD(ack->ack.epref)) {
2514		uni_msg_destroy(msg);
2515		uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2516		return;
2517	}
2518	if (ack->ack.epref.flag != 1) {
2519		uni_msg_destroy(msg);
2520		uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2521		return;
2522	}
2523	if ((p = uni_find_partyx(c, ack->ack.epref.epref, 0)) == NULL) {
2524		uni_msg_destroy(msg);
2525		uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
2526		return;
2527	}
2528
2529	uni_enq_party(p, SIGP_ADD_PARTY_ACK_request, cookie, msg, NULL);
2530}
2531
2532/*
2533 * Party-alerting.request from API in U7/U8/U10
2534 *
2535 * Q.2971:Call-Control-U 14/39 U7
2536 * Q.2971:Call-Control-U 15/39 U8
2537 * Q.2971:Call-Control-U 21/39 U10
2538 * Q.2971:Call-Control-N 8/39  N4
2539 * Q.2971:Call-Control-N 22/39 N10
2540 */
2541static void
2542unx_party_alerting_request(struct call *c, struct uni_msg *msg, uint32_t cookie)
2543{
2544	struct uniapi_party_alerting_request *alert =
2545	    uni_msg_rptr(msg, struct uniapi_party_alerting_request *);
2546	struct party *p;
2547
2548	if (!IE_ISGOOD(alert->alert.epref)) {
2549		uni_msg_destroy(msg);
2550		uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2551		return;
2552	}
2553	if (alert->alert.epref.flag != 1) {
2554		uni_msg_destroy(msg);
2555		uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2556		return;
2557	}
2558	if ((p = uni_find_partyx(c, alert->alert.epref.epref, 0)) == NULL) {
2559		uni_msg_destroy(msg);
2560		uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
2561		return;
2562	}
2563
2564	uni_enq_party(p, SIGP_PARTY_ALERTING_request, cookie, msg, NULL);
2565}
2566
2567/*
2568 * Add-party-rej.request from API in U7/U8/U10/N4/N10
2569 *
2570 * Q.2971:Call-Control-U 14/39 U7
2571 * Q.2971:Call-Control-U 15/39 U8
2572 * Q.2971:Call-Control-U 21/39 U10
2573 * Q.2971:Call-Control-N 8/39  N4
2574 * Q.2971:Call-Control-N 22/39 N10
2575 */
2576static void
2577unx_add_party_rej_request(struct call *c, struct uni_msg *msg, uint32_t cookie)
2578{
2579	struct uniapi_add_party_rej_request *rej =
2580	    uni_msg_rptr(msg, struct uniapi_add_party_rej_request *);
2581	struct party *p;
2582
2583	if (!IE_ISGOOD(rej->rej.epref)) {
2584		uni_msg_destroy(msg);
2585		uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2586		return;
2587	}
2588	if (rej->rej.epref.flag != 1) {
2589		uni_msg_destroy(msg);
2590		uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2591		return;
2592	}
2593	if ((p = uni_find_partyx(c, rej->rej.epref.epref, 0)) == NULL) {
2594		uni_msg_destroy(msg);
2595		uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
2596		return;
2597	}
2598
2599	uni_enq_party(p, SIGP_ADD_PARTY_REJ_request, cookie, msg, NULL);
2600}
2601
2602/*
2603 * Drop-party.request from API in U1-U10
2604 *
2605 * Q.2971:Call-Control-U 21/39 U10
2606 * Q.2971:Call-Control-U 26/39 U1-U9
2607 * Q.2971:Call-Control-N 22/39 N10
2608 * Q.2971:Call-Control-N 27/39 N1-N9
2609 */
2610static void
2611unx_drop_party_request(struct call *c, struct uni_msg *msg, uint32_t cookie)
2612{
2613	struct uniapi_drop_party_request *drop =
2614	    uni_msg_rptr(msg, struct uniapi_drop_party_request *);
2615	struct party *p;
2616
2617	if (!IE_ISGOOD(drop->drop.epref)) {
2618		uni_msg_destroy(msg);
2619		uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2620		return;
2621	}
2622	if ((p = uni_find_partyx(c, drop->drop.epref.epref, !drop->drop.epref.flag)) == NULL) {
2623		uni_msg_destroy(msg);
2624		uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
2625		return;
2626	}
2627
2628	uni_enq_party(p, SIGP_DROP_PARTY_request, cookie, msg, NULL);
2629}
2630
2631/*
2632 * Drop-party-ack.request from API in U1-U10
2633 *
2634 * Q.2971:Call-Control-U 21/39 U10
2635 * Q.2971:Call-Control-U 26/39 U1-U9
2636 * Q.2971:Call-Control-N 22/39 N10
2637 * Q.2971:Call-Control-N 27/39 N1-N9
2638 */
2639static void
2640unx_drop_party_ack_request(struct call *c, struct uni_msg *msg,
2641    uint32_t cookie)
2642{
2643	struct uniapi_drop_party_ack_request *ack =
2644	    uni_msg_rptr(msg, struct uniapi_drop_party_ack_request *);
2645	struct party *p;
2646
2647	if (!IE_ISGOOD(ack->ack.epref)) {
2648		uni_msg_destroy(msg);
2649		uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2650		return;
2651	}
2652	if ((p = uni_find_partyx(c, ack->ack.epref.epref, !ack->ack.epref.flag)) == NULL) {
2653		uni_msg_destroy(msg);
2654		uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
2655		return;
2656	}
2657
2658	uni_enq_party(p, SIGP_DROP_PARTY_ACK_request, cookie, msg, NULL);
2659}
2660
2661/*
2662 * ADD PARTY in U7/U8/U10
2663 *
2664 * Q.2971:Call-Control-U 14/39  U7
2665 * Q.2971:Call-Control-U 15/39  U8
2666 * Q.2971:Call-Control-U 21/39  U10
2667 * Q.2971:Call-Control-N 8/39   N4
2668 * Q.2971:Call-Control-N 21/39  N10
2669 *
2670 * Body already decoded
2671 * XXX check EPREF flag
2672 */
2673static void
2674unx_add_party(struct call *c, struct uni_msg *m, struct uni_all *u,
2675    int legal)
2676{
2677	struct uni_all *resp;
2678	struct uni_ierr *e1;
2679	struct party *p = NULL;
2680	enum verify vfy;
2681
2682	uni_mandate_epref(c->uni, &u->u.add_party.epref);
2683	MANDATE_IE(c->uni, u->u.add_party.called, UNI_IE_CALLED);
2684
2685	/*
2686	 * Do part of the verify handish: according to 9.5.7.2 we must send
2687	 * an ADD_PARTY_REJ if mandatory IEs are bad or missing instead of
2688	 * clearing the call. But we must send a STATUS, if it is the EPREF!
2689	 */
2690	if (IE_ISGOOD(u->u.add_party.epref)) {
2691		c->uni->cause.u.ie.len = 0;
2692		FOREACH_ERR(e1, c->uni) {
2693			if (e1->err == UNI_IERR_MIS) {
2694				MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER,
2695				    UNI_CAUSE_MANDAT);
2696				goto rej;
2697			}
2698		}
2699		FOREACH_ERR(e1, c->uni) {
2700			if (e1->man && e1->ie != UNI_IE_EPREF &&
2701			    e1->act == UNI_IEACT_DEFAULT) {
2702				MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER,
2703				    UNI_CAUSE_IE_INV);
2704  rej:
2705				uni_vfy_collect_ies(c->uni);
2706				if ((resp = UNI_ALLOC()) != NULL) {
2707					MK_MSG_RESP(resp, UNI_ADD_PARTY_REJ,
2708					   &u->u.hdr.cref);
2709					MK_IE_EPREF(resp->u.add_party_rej.epref,
2710					    u->u.add_party.epref.epref,
2711					    !u->u.add_party.epref.flag);
2712					resp->u.add_party_rej.cause =
2713					    c->uni->cause;
2714
2715					unx_send_add_party_rej(c, resp);
2716				}
2717				goto ignore;
2718			}
2719		}
2720		p = uni_find_partyx(c, u->u.add_party.epref.epref,
2721		    u->u.add_party.epref.flag);
2722	}
2723
2724	vfy = uni_verify(c->uni, u->u.hdr.act);
2725
2726	switch (vfy) {
2727
2728	  case VFY_CLR:
2729		uni_vfy_collect_ies(c->uni);
2730		clear_callD(c);
2731		goto ignore;
2732
2733	  case VFY_RAIM:
2734	  case VFY_RAI:
2735		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
2736		    map_callstate(c->cstate), &u->u.add_party.epref,
2737		    p ? p->state : UNI_EPSTATE_NULL);
2738		/* FALLTHRU */
2739	  case VFY_I:
2740		goto ignore;
2741
2742	  case VFY_RAP:
2743	  case VFY_RAPU:
2744		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
2745		    map_callstate(c->cstate), &u->u.add_party.epref,
2746		    UNI_EPSTATE_ADD_RCVD);
2747	  case VFY_OK:
2748		/* FALLTHRU */
2749		break;
2750	}
2751	if (!legal) {
2752		uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
2753		    &u->u.add_party.epref, -1);
2754		return;
2755	}
2756
2757	if (IE_ISGOOD(u->u.add_party.epref) && p == NULL &&
2758	    u->u.add_party.epref.flag) {
2759		IE_SETERROR(u->u.add_party.epref);
2760		(void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF,
2761		    u->u.add_party.epref.h.act, UNI_IERR_BAD);
2762	}
2763
2764	if (!IE_ISGOOD(u->u.add_party.epref)) {
2765		/* 9.5.3.2.2 */
2766		if (vfy == VFY_OK) {
2767			MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER,
2768			    UNI_CAUSE_IE_INV);
2769
2770			uni_respond_status_verify(c->uni, &u->u.hdr.cref,
2771			    map_callstate(c->cstate), NULL, 0);
2772		}
2773		goto ignore;
2774	}
2775
2776
2777	if (p == NULL && (p = uni_create_party(c, &u->u.add_party.epref))
2778	    == NULL)
2779		goto ignore;
2780
2781	uni_enq_party(p, SIGP_ADD_PARTY, 0, m, u);
2782	return;
2783
2784  ignore:
2785	uni_msg_destroy(m);
2786	UNI_FREE(u);
2787}
2788
2789/*
2790 * ADD PARTY ACKNOWLEDGE
2791 *
2792 * Q.2971:Call-Control-U 21/39 U10
2793 * Q.2971:Call-Control-N 15/39 N8
2794 * Q.2971:Call-Control-N 22/39 N10
2795 */
2796static void
2797un10n8_add_party_ack(struct call *c, struct uni_msg *m, struct uni_all *u,
2798    int legal)
2799{
2800	struct party *p = NULL;
2801
2802	if (IE_ISGOOD(u->u.add_party_ack.epref)) {
2803		if (u->u.add_party_ack.epref.flag == 0) {
2804			IE_SETERROR(u->u.add_party_ack.epref);
2805			(void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF,
2806			    u->u.add_party_ack.epref.h.act, UNI_IERR_BAD);
2807		} else {
2808	    		p = uni_find_partyx(c, u->u.add_party_ack.epref.epref, 1);
2809			if (p == NULL) {
2810				respond_drop_party_ack(c,
2811				    &u->u.add_party_ack.epref,
2812				    UNI_CAUSE_ENDP_INV);
2813				goto ignore;
2814			}
2815		}
2816	}
2817	uni_mandate_epref(c->uni, &u->u.add_party_ack.epref);
2818
2819	switch (uni_verify(c->uni, u->u.hdr.act)) {
2820
2821	  case VFY_CLR:
2822		uni_vfy_collect_ies(c->uni);
2823		clear_callD(c);
2824		goto ignore;
2825
2826	  case VFY_RAIM:
2827	  case VFY_RAI:
2828	  report:
2829		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
2830		    map_callstate(c->cstate), &u->u.add_party_ack.epref,
2831		    p ? p->state : UNI_EPSTATE_NULL);
2832	  case VFY_I:
2833		goto ignore;
2834
2835	  case VFY_RAP:
2836	  case VFY_RAPU:
2837		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
2838		    map_callstate(c->cstate), &u->u.add_party_ack.epref,
2839		    p ? UNI_EPSTATE_ACTIVE : UNI_EPSTATE_NULL);
2840		if (!IE_ISGOOD(u->u.party_alerting.epref))
2841			/* See below */
2842			goto ignore;
2843		break;
2844	  case VFY_OK:
2845		if (!IE_ISGOOD(u->u.party_alerting.epref))
2846			/* this happens when the EPREF has bad format.
2847			 * The rules require us the message to be ignored
2848			 * (9.5.3.2.2e) and to report status.
2849			 */
2850			goto report;
2851		break;
2852	}
2853	if (legal) {
2854		/* p is != NULL here */
2855		uni_enq_party(p, SIGP_ADD_PARTY_ACK, 0, m, u);
2856		return;
2857	}
2858	if (p == NULL)
2859		/* Q.2971 9.5.3.2.3a) */
2860		respond_drop_party_ack(c, &u->u.add_party_ack.epref,
2861		    UNI_CAUSE_ENDP_INV);
2862	else
2863		uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
2864		    &u->u.add_party_ack.epref, p->state);
2865
2866  ignore:
2867	uni_msg_destroy(m);
2868	UNI_FREE(u);
2869}
2870
2871/*
2872 * Make the EPREF action default
2873 */
2874static void
2875default_act_epref(struct uni *uni, struct uni_ie_epref *epref)
2876{
2877	struct uni_ierr *e;
2878
2879	FOREACH_ERR(e, uni)
2880		if (e->ie == UNI_IE_EPREF) {
2881			e->act = UNI_IEACT_DEFAULT;
2882			break;
2883		}
2884	epref->h.act = UNI_IEACT_DEFAULT;
2885}
2886
2887/*
2888 * PARTY ALERTING message
2889 *
2890 * Q.2971:Call-Control-U 9/39   U4
2891 * Q.2971:Call-Control-U 21/39  U10
2892 * Q.2971:Call-Control-N 12/39  N7
2893 * Q.2971:Call-Control-N 15/39  N8
2894 * Q.2971:Call-Control-N 22/39  N10
2895 */
2896static void
2897unx_party_alerting(struct call *c, struct uni_msg *m, struct uni_all *u,
2898    int legal)
2899{
2900	struct party *p = NULL;
2901
2902	if (IE_ISGOOD(u->u.party_alerting.epref)) {
2903		if (u->u.party_alerting.epref.flag == 0) {
2904			IE_SETERROR(u->u.party_alerting.epref);
2905			(void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF,
2906			    u->u.party_alerting.epref.h.act, UNI_IERR_BAD);
2907		} else {
2908	    		p = uni_find_partyx(c, u->u.party_alerting.epref.epref, 1);
2909			if (p == NULL) {
2910				respond_drop_party_ack(c,
2911				    &u->u.party_alerting.epref,
2912				    UNI_CAUSE_ENDP_INV);
2913				goto ignore;
2914			}
2915		}
2916	}
2917	uni_mandate_epref(c->uni, &u->u.party_alerting.epref);
2918
2919	switch (uni_verify(c->uni, u->u.hdr.act)) {
2920
2921	  case VFY_CLR:
2922		uni_vfy_collect_ies(c->uni);
2923		clear_callD(c);
2924		goto ignore;
2925
2926	  case VFY_RAIM:
2927	  case VFY_RAI:
2928	  report:
2929		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
2930		    map_callstate(c->cstate), &u->u.party_alerting.epref,
2931		    p ? p->state : UNI_EPSTATE_NULL);
2932	  case VFY_I:
2933		goto ignore;
2934
2935	  case VFY_RAP:
2936	  case VFY_RAPU:
2937		uni_respond_status_verify(c->uni, &u->u.hdr.cref,
2938		    map_callstate(c->cstate), &u->u.party_alerting.epref,
2939		    p ? UNI_EPSTATE_ALERT_RCVD : UNI_EPSTATE_NULL);
2940		if (!IE_ISGOOD(u->u.party_alerting.epref))
2941			/* See below */
2942			goto ignore;
2943		break;
2944
2945	  case VFY_OK:
2946		if (!IE_ISGOOD(u->u.party_alerting.epref))
2947			/* The rules require us the message to be ignored
2948			 * (9.5.3.2.2e) and to report status.
2949			 */
2950			goto report;
2951		break;
2952	}
2953	if (legal) {
2954		/* p is != NULL here */
2955		uni_enq_party(p, SIGP_PARTY_ALERTING, 0, m, u);
2956		return;
2957	}
2958	if (p == NULL)
2959		/* Q.2971 9.5.3.2.3a) */
2960		respond_drop_party_ack(c, &u->u.party_alerting.epref,
2961		    UNI_CAUSE_ENDP_INV);
2962	else
2963		uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
2964		    &u->u.party_alerting.epref, p->state);
2965
2966  ignore:
2967	uni_msg_destroy(m);
2968	UNI_FREE(u);
2969}
2970
2971/*
2972 * Handle a bad/missing cause in a DROP_PARTY_ACK or ADD_PARTY_REJ
2973 *
2974 * If the IE is missing or bad and the action is defaulted handle as
2975 * cause #1 according to 9.5.7.1/2.
2976 * Otherwise keep the IE.
2977 */
2978static void
2979handle_bad_drop_cause(struct call *c, struct uni_ie_cause *cause, int mkcause)
2980{
2981
2982	if (IE_ISGOOD(*cause))
2983		return;
2984
2985	if (!IE_ISPRESENT(*cause)) {
2986		/* 9.5.7.1 */
2987		/* cannot make cause here because we need the 96 error */
2988		uni_vfy_remove_cause(c->uni);
2989		return;
2990	}
2991	if (cause->h.act != UNI_IEACT_DEFAULT)
2992		return;
2993
2994	/* 9.5.7.2 */
2995	uni_vfy_remove_cause(c->uni);
2996	if (mkcause)
2997		MK_IE_CAUSE(*cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_UNSPEC);
2998}
2999
3000/*
3001 * ADD PARTY REJ from party control
3002 * Q.2971:Call-Control-U 21/39
3003 * Q.2971:Call-Control-U 24/39
3004 */
3005static void
3006unx_send_add_party_rej(struct call *c, struct uni_all *u)
3007{
3008
3009	if (uni_party_act_count(c, 2) == 0) {
3010		if (c->cstate != CALLST_U11 && c->cstate != CALLST_N12) {
3011			c->uni->cause = u->u.add_party_rej.cause;
3012			clear_callD(c);
3013		}
3014	} else
3015		(void)uni_send_output(u, c->uni);
3016	UNI_FREE(u);
3017}
3018
3019/*
3020 * ADD_PARTY_REJECT in U4/U10
3021 *
3022 * Q.2971:Call-Control-U 9/39 U4
3023 * Q.2971:Call-Control-U 21/39 U10
3024 * Q.2971:Call-Control-N 12/39 N7
3025 * Q.2971:Call-Control-N 15/39 N8
3026 * Q.2971:Call-Control-N 22/39 N10
3027 */
3028static void
3029unx_add_party_rej(struct call *c, struct uni_msg *m, struct uni_all *u,
3030    int legal)
3031{
3032	struct uni_add_party_rej *ar = &u->u.add_party_rej;
3033	struct party *p;
3034
3035	if (IE_ISGOOD(ar->epref)) {
3036		p = uni_find_partyx(c, ar->epref.epref, ar->epref.flag);
3037		if (p == NULL)
3038			goto ignore;
3039
3040		if (legal) {
3041			handle_bad_drop_cause(c, &ar->cause, 0);
3042			uni_vfy_remove_unknown(c->uni);
3043			switch (uni_verify(c->uni, u->u.hdr.act)) {
3044
3045			  case VFY_CLR:
3046				goto clear;
3047
3048			  case VFY_RAIM:
3049			  case VFY_RAI:
3050				uni_respond_status_verify(c->uni,
3051				    &u->u.hdr.cref, map_callstate(c->cstate),
3052				    &ar->epref, p->state);
3053			  case VFY_I:
3054				goto ignore;
3055
3056			  case VFY_RAPU:
3057				uni_vfy_collect_ies(c->uni);
3058				break;
3059
3060			  case VFY_RAP:
3061				uni_respond_status_verify(c->uni,
3062				    &u->u.hdr.cref, map_callstate(c->cstate),
3063				    &ar->epref, p->state);
3064			  case VFY_OK:
3065				break;
3066			}
3067			uni_enq_party(p, SIGP_ADD_PARTY_REJ, 0, m, u);
3068			return;
3069		}
3070		uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3071		    &ar->epref, -1);
3072		return;
3073	}
3074
3075	/* Q.2971: 9.5.3.2.1 last paragraph
3076	 *         9.5.3.2.2 second to last paragraph
3077	 * Make the action indicator default.
3078	 */
3079	default_act_epref(c->uni, &ar->epref);
3080	if (!IE_ISPRESENT(ar->epref))
3081		uni_mandate_ie(c->uni, UNI_IE_EPREF);
3082	(void)uni_verify(c->uni, u->u.hdr.act);
3083
3084  clear:
3085	uni_vfy_collect_ies(c->uni);
3086	clear_callD(c);
3087
3088  ignore:
3089	uni_msg_destroy(m);
3090	UNI_FREE(u);
3091}
3092
3093/*
3094 * DROP_PARTY
3095 *
3096 * Q.2971:Call-Control-U 26/39 Ux
3097 * Q.2971:Call-Control-U 21/39 U10
3098 * Q.2971:Call-Control-N 27/39 Nx
3099 * Q.2971:Call-Control-N 22/39 N10
3100 */
3101static void
3102unx_drop_party(struct call *c, struct uni_msg *m, struct uni_all *u, int legal)
3103{
3104	struct uni_drop_party *dp = &u->u.drop_party;
3105	struct party *p;
3106	struct uni_ierr *e;
3107
3108	if (IE_ISGOOD(dp->epref)) {
3109		p = uni_find_partyx(c, dp->epref.epref, dp->epref.flag);
3110		if (p == NULL) {
3111			respond_drop_party_ack(c, &dp->epref,
3112			    UNI_CAUSE_ENDP_INV);
3113			goto ignore;
3114		}
3115		handle_bad_drop_cause(c, &dp->cause, 0);
3116		uni_vfy_remove_unknown(c->uni);
3117		switch (uni_verify(c->uni, u->u.hdr.act)) {
3118
3119		  case VFY_CLR:
3120			goto clear;
3121
3122		  case VFY_RAIM:
3123		  case VFY_RAI:
3124			uni_respond_status_verify(c->uni, &u->u.hdr.cref,
3125			    map_callstate(c->cstate),
3126			    &u->u.drop_party.epref, p->state);
3127		  case VFY_I:
3128			goto ignore;
3129
3130		  case VFY_RAPU:
3131			uni_vfy_collect_ies(c->uni);
3132			break;
3133
3134		  case VFY_RAP:
3135			uni_respond_status_verify(c->uni, &u->u.hdr.cref,
3136			    map_callstate(c->cstate),
3137			    &dp->epref, UNI_EPSTATE_DROP_RCVD);
3138		  case VFY_OK:
3139			break;
3140		}
3141		if (legal) {
3142			uni_enq_party(p, SIGP_DROP_PARTY, 0, m, u);
3143			return;
3144		}
3145		uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, &dp->epref, -1);
3146		goto ignore;
3147	}
3148
3149	/* Q.2971: 9.5.3.2.1 last paragraph
3150	 *         9.5.3.2.2 second to last paragraph
3151	 * Make the action indicator default.
3152	 */
3153	FOREACH_ERR(e, c->uni)
3154		if (e->ie == UNI_IE_EPREF) {
3155			e->act = UNI_IEACT_DEFAULT;
3156			break;
3157		}
3158	dp->epref.h.act = UNI_IEACT_DEFAULT;
3159
3160	if (!IE_ISPRESENT(dp->epref))
3161		uni_mandate_ie(c->uni, UNI_IE_EPREF);
3162	(void)uni_verify(c->uni, u->u.hdr.act);
3163
3164  clear:
3165	uni_vfy_collect_ies(c->uni);
3166	clear_callD(c);
3167	uni_msg_destroy(m);
3168	UNI_FREE(u);
3169	return;
3170
3171  ignore:
3172	uni_msg_destroy(m);
3173	UNI_FREE(u);
3174}
3175
3176/*
3177 * DROP_PARTY_ACK
3178 *
3179 * Q.2971:Call-Control-U 26/39 Ux
3180 * Q.2971:Call-Control-U 21/39 U10
3181 * Q.2971:Call-Control-N 27/39 Nx
3182 * Q.2971:Call-Control-N 22/39 N10
3183 */
3184static void
3185unx_drop_party_ack(struct call *c, struct uni_msg *m, struct uni_all *u,
3186    int legal)
3187{
3188	struct party *p;
3189	struct uni_drop_party_ack *ack = &u->u.drop_party_ack;
3190
3191	if (IE_ISGOOD(u->u.drop_party_ack.epref)) {
3192		p = uni_find_partyx(c, ack->epref.epref, ack->epref.flag);
3193		if (p != NULL) {
3194			handle_bad_drop_cause(c, &ack->cause, 1);
3195			uni_vfy_remove_unknown(c->uni);
3196			switch (uni_verify(c->uni, u->u.hdr.act)) {
3197
3198			  case VFY_CLR:
3199				goto clear;
3200
3201			  case VFY_RAIM:
3202			  case VFY_RAI:
3203				uni_respond_status_verify(c->uni,
3204				    &u->u.hdr.cref, map_callstate(c->cstate),
3205				    &ack->epref, p->state);
3206			  case VFY_I:
3207				goto ignore;
3208
3209			  case VFY_RAP:
3210				uni_respond_status_verify(c->uni,
3211				    &u->u.hdr.cref, map_callstate(c->cstate),
3212				    &ack->epref, UNI_EPSTATE_NULL);
3213			  case VFY_RAPU:
3214			  case VFY_OK:
3215				break;
3216			}
3217			if (legal) {
3218				uni_enq_party(p, SIGP_DROP_PARTY_ACK, 0, m, u);
3219				return;
3220			}
3221			uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3222			    &ack->epref, -1);
3223		}
3224		goto ignore;
3225	}
3226
3227	/* Q.2971: 9.5.3.2.1 last paragraph
3228	 *         9.5.3.2.2 second to last paragraph
3229	 */
3230	(void)uni_verify(c->uni, u->u.hdr.act);
3231	MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_IE_INV);
3232
3233  clear:
3234	uni_vfy_collect_ies(c->uni);
3235	clear_callD(c);
3236	uni_msg_destroy(m);
3237	UNI_FREE(u);
3238	return;
3239
3240  ignore:
3241	uni_msg_destroy(m);
3242	UNI_FREE(u);
3243}
3244
3245/**********************************************************************/
3246
3247/*
3248 * Bad or unrecognized message.
3249 *
3250 * Q.2971:Call-Control-U 35/39
3251 */
3252void
3253uni_bad_message(struct call *c, struct uni_all *u, u_int cause,
3254    struct uni_ie_epref *epref, int ps)
3255{
3256	struct uni_all *resp;
3257	struct party *p;
3258
3259	if ((u->u.hdr.act == UNI_MSGACT_CLEAR &&
3260	    (c->cstate == CALLST_U11 ||
3261	     c->cstate == CALLST_U12 ||
3262	     c->cstate == CALLST_N11 ||
3263	     c->cstate == CALLST_N12)) ||
3264	    u->u.hdr.act == UNI_MSGACT_IGNORE)
3265		return;
3266
3267	MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, cause);
3268	ADD_CAUSE_MTYPE(c->uni->cause, u->mtype);
3269
3270	if (u->u.hdr.act == UNI_MSGACT_CLEAR) {
3271		clear_callD(c);
3272		return;
3273	}
3274
3275	/*
3276	 * Send STATUS
3277	 */
3278	if ((resp = UNI_ALLOC()) != NULL) {
3279		MK_MSG_RESP(resp, UNI_STATUS, &u->u.hdr.cref);
3280		MK_IE_CALLSTATE(resp->u.status.callstate,
3281		    map_callstate(c->cstate));
3282		resp->u.status.cause = c->uni->cause;
3283
3284		if (epref != NULL && IE_ISGOOD(*epref)) {
3285			MK_IE_EPREF(resp->u.status.epref, epref->epref, !epref->flag);
3286			if (ps == -1) {
3287				p = uni_find_party(c, epref);
3288				if (p == NULL)
3289					ps = UNI_EPSTATE_NULL;
3290				else
3291					ps = p->state;
3292			}
3293			MK_IE_EPSTATE(resp->u.status.epstate, ps);
3294		}
3295		(void)uni_send_output(resp, c->uni);
3296
3297		UNI_FREE(resp);
3298	}
3299}
3300
3301/**********************************************************************/
3302
3303/*
3304 * Unknown message in any state.
3305 *
3306 * Q.2971:Call-Control 35/39
3307 * Q.2971:Call-Control 36/39
3308 */
3309static void
3310unx_unknown(struct call *c, struct uni_msg *m, struct uni_all *u)
3311{
3312	/*
3313	 * Unrecognized message. Cannot call verify here, because
3314	 * it doesn't know about unrecognized messages.
3315	 */
3316	if (u->u.hdr.act == UNI_MSGACT_CLEAR) {
3317		MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER,
3318		    UNI_CAUSE_MTYPE_NIMPL);
3319		ADD_CAUSE_MTYPE(c->uni->cause, u->mtype);
3320		clear_callD(c);
3321	} else if(u->u.hdr.act == UNI_MSGACT_IGNORE) {
3322		;
3323	} else {
3324		(void)uni_decode_body(m, u, &c->uni->cx);
3325		uni_bad_message(c, u, UNI_CAUSE_MTYPE_NIMPL,
3326		    &u->u.unknown.epref, -1);
3327	}
3328	uni_msg_destroy(m);
3329	UNI_FREE(u);
3330}
3331/**********************************************************************/
3332
3333void
3334uni_sig_call(struct call *c, enum call_sig sig, uint32_t cookie,
3335    struct uni_msg *msg, struct uni_all *u)
3336{
3337	if (sig >= SIGC_END) {
3338		VERBOSE(c->uni, UNI_FAC_ERR, 1,
3339		    "Signal %d outside of range to Call-Control", sig);
3340		if (msg)
3341			uni_msg_destroy(msg);
3342		if (u)
3343			UNI_FREE(u);
3344		return;
3345	}
3346
3347	VERBOSE(c->uni, UNI_FAC_CALL, 1, "Signal %s in state %s of call %u/%s"
3348	    "; cookie %u", call_sigs[sig], callstates[c->cstate].name, c->cref,
3349	    c->mine ? "mine" : "his", cookie);
3350
3351	switch (sig) {
3352
3353	  case SIGC_LINK_RELEASE_indication:
3354		if (c->cstate == CALLST_U10 || c->cstate == CALLST_N10)
3355			/* Q.2971:Call-Control-U 36/39 */
3356			/* Q.2971:Call-Control-N 20/39 */
3357			un10_link_release_indication(c);
3358		else
3359			/* Q.2971:Call-Control-U 36/39 */
3360			/* Q.2971:Call-Control-N 37/39 */
3361			unx_link_release_indication(c);
3362		break;
3363
3364	  case SIGC_LINK_ESTABLISH_ERROR_indication:
3365		if (c->cstate != CALLST_U10 && c->cstate != CALLST_N10) {
3366			VERBOSE(c->uni, UNI_FAC_ERR, 1,
3367			    "link-establish-error.indication in cs=%s",
3368			    callstates[c->cstate].name);
3369			break;
3370		}
3371		/* Q.2971:Call-Control-U 19/39 */
3372		/* Q.2971:Call-Control-N 20/39 */
3373		un10_link_establish_error_indication(c);
3374		break;
3375
3376	  case SIGC_LINK_ESTABLISH_indication:
3377		switch (c->cstate) {
3378
3379		  case CALLST_U1: case CALLST_N1:
3380		  case CALLST_U3: case CALLST_N3:
3381		  case CALLST_U4: case CALLST_N4:
3382		  case CALLST_U6: case CALLST_N6:
3383		  case CALLST_U7: case CALLST_N7:
3384		  case CALLST_U8: case CALLST_N8:
3385		  case CALLST_U9: case CALLST_N9:
3386			/* Q.2971:Call-Control-U 36/39 */
3387			/* Q.2971:Call-Control-N 37/39 */
3388			unx_link_establish_indication(c);
3389			break;
3390
3391		  case CALLST_U10: case CALLST_N10:
3392			/* Q.2971:Call-Control-U 19/39 */
3393			/* Q.2971:Call-Control-N 20/39 */
3394			un10_link_establish_indication(c);
3395			break;
3396
3397		  case CALLST_U11: case CALLST_N11:
3398		  case CALLST_U12: case CALLST_N12:
3399			/* Q.2971:Call-Control-U 36/39 */
3400			/* Q.2971:Call-Control-N 37/39 */
3401			break;
3402
3403		  default:
3404			VERBOSE(c->uni, UNI_FAC_ERR, 1,
3405			    "link-establish.indication in cs=%s",
3406			    callstates[c->cstate].name);
3407		}
3408		break;
3409
3410	  case SIGC_LINK_ESTABLISH_confirm:
3411		if (c->cstate != CALLST_U10 && c->cstate != CALLST_N10) {
3412			VERBOSE(c->uni, UNI_FAC_ERR, 1,
3413			    "link-establish.confirm in cs=%s",
3414			    callstates[c->cstate].name);
3415			break;
3416		}
3417		/* Q.2971:Call-Control-U 19/39 */
3418		/* Q.2971:Call-Control-N 20/39 */
3419		un10_link_establish_confirm(c);
3420		break;
3421
3422	  case SIGC_UNKNOWN:
3423		/* Q.2971:Call-Control 35/39 */
3424		/* Q.2971:Call-Control 36/39 */
3425		unx_unknown(c, msg, u);
3426		break;
3427
3428	  case SIGC_SETUP:
3429		if (c->cstate != CALLST_NULL) {
3430			(void)uni_decode_body(msg, u, &c->uni->cx);
3431			uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3432			    &u->u.setup.epref, -1);
3433			goto drop;
3434		}
3435		if (c->uni->proto == UNIPROTO_UNI40N)
3436			/* Q.2971:Call-Control-N 4/39 */
3437			un0_setup(c, msg, u, CALLST_N1);
3438		else
3439			/* Q.2971:Call-Control-U 4/39 */
3440			un0_setup(c, msg, u, CALLST_U6);
3441		break;
3442
3443	  case SIGC_CALL_PROC:
3444		if (c->cstate == CALLST_U1) {
3445			/* Q.2971:Call-Control-U 6/39 */
3446			u1n6_call_proc(c, msg, u, CALLST_U3);
3447			break;
3448		}
3449		if (c->cstate == CALLST_N6) {
3450			/* Q.2971:Call-Control-N 11/39 */
3451			u1n6_call_proc(c, msg, u, CALLST_N9);
3452			break;
3453		}
3454		(void)uni_decode_body(msg, u, &c->uni->cx);
3455		uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3456		    &u->u.call_proc.epref, -1);
3457		goto drop;
3458
3459	  case SIGC_ALERTING:
3460		if (c->cstate == CALLST_U1 || c->cstate == CALLST_U3) {
3461			/* Q.2971:Call-Control-U 37/39 (U1) */
3462			/* Q.2971:Call-Control-U 7/39 (U3) */
3463			unx_alerting(c, msg, u, CALLST_U4);
3464			break;
3465		}
3466		if (c->cstate == CALLST_N6) {
3467			/* Q.2971:Call-Control-N 9/39 (N6) */
3468			/* Q.2971:Call-Control-N 17/39 (N9) */
3469			unx_alerting(c, msg, u, CALLST_N7);
3470			break;
3471		}
3472		(void)uni_decode_body(msg, u, &c->uni->cx);
3473		uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3474		    &u->u.alerting.epref, -1);
3475		goto drop;
3476
3477	  case SIGC_CONNECT:
3478		if (c->cstate == CALLST_U1 || c->cstate == CALLST_U3 ||
3479		    c->cstate == CALLST_U4) {
3480			/* Q.2971:Call-Control-U 7-8/39  (U3) */
3481			/* Q.2971:Call-Control-U 11/39   (U4) */
3482			/* Q.2971:Call-Control-U 37/39   (U1) */
3483			unx_connect(c, msg, u, CALLST_U10);
3484			break;
3485		}
3486		if (c->cstate == CALLST_N6 || c->cstate == CALLST_N7 ||
3487		    c->cstate == CALLST_N9) {
3488			/* Q.2971:Call-Control-N 9-10/39 (N6) */
3489			/* Q.2971:Call-Control-N 14/39   (N7) */
3490			/* Q.2971:Call-Control-N 17/39   (N9) */
3491			unx_connect(c, msg, u, CALLST_N8);
3492			break;
3493		}
3494		(void)uni_decode_body(msg, u, &c->uni->cx);
3495		uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3496		    &u->u.connect.epref, -1);
3497		goto drop;
3498
3499	  case SIGC_CONNECT_ACK:
3500		if (c->cstate == CALLST_U8) {
3501			/* Q.2971:Call-Control-U 15-16/39 */
3502			u8_connect_ack(c, msg, u, CALLST_U10);
3503			break;
3504		}
3505		if (c->cstate == CALLST_N10) {
3506			/* Q.2971:Call-Control-N 18/39 */
3507			n10_connect_ack(c, msg, u);
3508			break;
3509		}
3510		uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, NULL, 0);
3511		goto drop;
3512
3513	  case SIGC_RELEASE:
3514		switch (c->cstate) {
3515
3516		  default:
3517			uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, NULL, 0);
3518			goto drop;
3519
3520		  case CALLST_U11:
3521		  case CALLST_N12:
3522			/* Q.2971:Call-Control-U 28/39 */
3523			/* Q.2971:Call-Control-N 30/39 */
3524			u11n12_release(c, msg, u);
3525			break;
3526
3527		  case CALLST_U1:
3528		  case CALLST_U3:
3529		  case CALLST_U4:
3530		  case CALLST_U6:
3531		  case CALLST_U7:
3532		  case CALLST_U8:
3533		  case CALLST_U9:
3534		  case CALLST_U10:
3535		  case CALLST_U12:
3536			/* Q.2971:Call-Control-U 25/39 */
3537			unx_release(c, msg, u, CALLST_U12);
3538			break;
3539
3540		  case CALLST_N1:
3541		  case CALLST_N3:
3542		  case CALLST_N4:
3543		  case CALLST_N6:
3544		  case CALLST_N7:
3545		  case CALLST_N8:
3546		  case CALLST_N9:
3547		  case CALLST_N10:
3548		  case CALLST_N11:
3549			/* Q.2971:Call-Control-N 26/39 */
3550			unx_release(c, msg, u, CALLST_N11);
3551			break;
3552		}
3553		break;
3554
3555	  case SIGC_RELEASE_COMPL:
3556		/* Q.2971:Call-Control-U 25/39 */
3557		/* Q.2971:Call-Control-N 26/39 */
3558		unx_release_compl(c, msg, u);
3559		break;
3560
3561	  case SIGC_NOTIFY:
3562		/* Q.2971:Call-Control-U 18/39 */
3563		/* Q.2971:Call-Control-N 19/39 */
3564		unx_notify(c, msg, u);
3565		break;
3566
3567	  case SIGC_STATUS:
3568		if (c->cstate == CALLST_U11 || c->cstate == CALLST_U12 ||
3569		    c->cstate == CALLST_N11 || c->cstate == CALLST_N12) {
3570			/* Q.2971:Call-Control-U 29/39 (U11) */
3571			/* Q.2971:Call-Control-U 30/39 (U12) */
3572			/* Q.2971:Call-Control-N 29/39 (N11) */
3573			/* Q.2971:Call-Control-N 31/39 (N12) */
3574			un11un12_status(c, msg, u);
3575			break;
3576		}
3577		/* Q.2971:Call-Control-U 32/39 */
3578		/* Q.2971:Call-Control-N 33/39 */
3579		unx_status(c, msg, u);
3580		break;
3581
3582	  case SIGC_STATUS_ENQ:
3583		/* Q.2971:Call-Control-U 31/39 */
3584		/* Q.2971:Call-Control-N 32/39 */
3585		unx_status_enq(c, msg, u);
3586		break;
3587
3588	  case SIGC_ADD_PARTY:
3589		(void)uni_decode_body(msg, u, &c->uni->cx);
3590
3591		if (c->type != CALL_LEAF && c->type != CALL_ROOT) {
3592			uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3593			    &u->u.add_party.epref, UNI_EPSTATE_NULL);
3594			goto drop;
3595		}
3596		switch (c->cstate) {
3597		  case CALLST_U7:
3598		  case CALLST_U8:
3599		  case CALLST_U10:
3600		  case CALLST_N4:
3601		  case CALLST_N10:
3602			/* Q.2971:Call-Control-U 14/39  U7 */
3603			/* Q.2971:Call-Control-U 15/39  U8 */
3604			/* Q.2971:Call-Control-U 21/39  U10 */
3605			/* Q.2971:Call-Control-N 8/39   N4 */
3606			/* Q.2971:Call-Control-N 21/39  N10 */
3607			unx_add_party(c, msg, u, 1);
3608			break;
3609
3610		  default:
3611			unx_add_party(c, msg, u, 0);
3612			goto drop;
3613		}
3614		break;
3615
3616	  case SIGC_PARTY_ALERTING:
3617		(void)uni_decode_body(msg, u, &c->uni->cx);
3618
3619		if (c->type != CALL_ROOT) {
3620			uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3621			    &u->u.party_alerting.epref, -1);
3622			goto drop;
3623		}
3624		switch (c->cstate) {
3625
3626		  default:
3627			/* Q.2971 9.5.3.2.3a) */
3628			unx_party_alerting(c, msg, u, 0);
3629			break;
3630
3631		  case CALLST_U4:
3632		  case CALLST_U10:
3633			/* Q.2971:Call-Control-U 9/39   U4 */
3634			/* Q.2971:Call-Control-U 21/39  U10 */
3635			/* Q.2971:Call-Control-N 12/39  N7 */
3636			/* Q.2971:Call-Control-N 15/39  N8 */
3637			/* Q.2971:Call-Control-N 22/39  N10 */
3638			unx_party_alerting(c, msg, u, 1);
3639			break;
3640		}
3641		break;
3642
3643	  case SIGC_ADD_PARTY_ACK:
3644		(void)uni_decode_body(msg, u, &c->uni->cx);
3645
3646		if (c->type != CALL_ROOT) {
3647			uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3648			    &u->u.add_party_rej.epref, -1);
3649			goto drop;
3650		}
3651		switch (c->cstate) {
3652
3653		  case CALLST_U10:
3654			/* Q.2971:Call-Control-U 21/39 U10 */
3655			/* Q.2971:Call-Control-N 15/39 N8 */
3656			/* Q.2971:Call-Control-N 22/39 N10 */
3657			un10n8_add_party_ack(c, msg, u, 1);
3658			break;
3659
3660		  default:
3661			/* Q.2971 9.5.3.2.3a) */
3662			un10n8_add_party_ack(c, msg, u, 0);
3663			break;
3664		}
3665		break;
3666
3667	  case SIGC_ADD_PARTY_REJ:
3668		(void)uni_decode_body(msg, u, &c->uni->cx);
3669
3670		if (c->type != CALL_ROOT) {
3671			uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3672			    &u->u.add_party_rej.epref, -1);
3673			goto drop;
3674		}
3675		switch (c->cstate) {
3676
3677		  case CALLST_U4:
3678	     	  case CALLST_U10:
3679		  case CALLST_N7:
3680		  case CALLST_N8:
3681		  case CALLST_N10:
3682			/* Q.2971:Call-Control-U 9/39 U4 */
3683			/* Q.2971:Call-Control-U 21/39 U10 */
3684			/* Q.2971:Call-Control-N 12/39 N7 */
3685			/* Q.2971:Call-Control-N 15/39 N8 */
3686			/* Q.2971:Call-Control-N 22/39 N10 */
3687			unx_add_party_rej(c, msg, u, 1);
3688			break;
3689
3690		  default:
3691			/* Q.2971: 9.5.3.2.3b */
3692			unx_add_party_rej(c, msg, u, 0);
3693			break;
3694		}
3695		break;
3696
3697	  case SIGC_DROP_PARTY:
3698		(void)uni_decode_body(msg, u, &c->uni->cx);
3699
3700		if (c->type != CALL_ROOT && c->type != CALL_LEAF) {
3701			uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3702			    &u->u.drop_party.epref, -1);
3703			goto drop;
3704		}
3705		switch (c->cstate) {
3706		  case CALLST_U11:
3707		  case CALLST_U12:
3708		  case CALLST_N11:
3709		  case CALLST_N12:
3710			/* Q.2971:Call-Control-U 28/39 U11 */
3711			/* Q.2971:Call-Control-U 30/39 U12 */
3712			/* Q.2971:Call-Control-N 29/39 N11 */
3713			/* Q.2971:Call-Control-N 30/39 N12 */
3714			goto drop;
3715
3716		  case CALLST_NULL:
3717			uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3718			    &u->u.drop_party.epref, UNI_EPSTATE_NULL);
3719			goto drop;
3720
3721		  case CALLST_U3:
3722		  case CALLST_N3:
3723			/* L3MU_17_38 */
3724			unx_drop_party(c, msg, u, 0);
3725			break;
3726
3727		  case CALLST_U8:
3728			if (c->uni->sb_tb) {
3729				/* L3MU_06_0[3-6] */
3730				unx_drop_party(c, msg, u, 0);
3731				break;
3732			}
3733			/* FALLTHRU */
3734
3735		  default:
3736			/* Q.2971:Call-Control-U 26/39 Ux */
3737			/* Q.2971:Call-Control-U 21/39 U10 */
3738			/* Q.2971:Call-Control-N 27/39 Nx */
3739			/* Q.2971:Call-Control-N 21/39 N10 */
3740			unx_drop_party(c, msg, u, 1);
3741			break;
3742		}
3743		break;
3744
3745	  case SIGC_DROP_PARTY_ACK:
3746		(void)uni_decode_body(msg, u, &c->uni->cx);
3747
3748		if (c->type != CALL_ROOT && c->type != CALL_LEAF) {
3749			uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3750			    &u->u.drop_party_ack.epref, -1);
3751			goto drop;
3752		}
3753		switch (c->cstate) {
3754
3755		  case CALLST_U11:
3756		  case CALLST_U12:
3757			/* Q.2971:Call-Control-U 28/39 U11 */
3758			/* Q.2971:Call-Control-U 30/39 U12 */
3759			/* Q.2971:Call-Control-N 29/39 N11 */
3760			/* Q.2971:Call-Control-N 30/39 N12 */
3761			goto drop;
3762
3763		  case CALLST_NULL:
3764			uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3765			    &u->u.drop_party.epref, UNI_EPSTATE_NULL);
3766			goto drop;
3767
3768		  case CALLST_U4:
3769		  case CALLST_N4:
3770		  case CALLST_U7:
3771		  case CALLST_N7:
3772		  case CALLST_U8:
3773		  case CALLST_N8:
3774		  case CALLST_U10:
3775		  case CALLST_N10:
3776			/* Q.2971:Call-Control-U 26/39 Ux */
3777			/* Q.2971:Call-Control-U 21/39 U10 */
3778			/* Q.2971:Call-Control-N 27/39 Nx */
3779			/* Q.2971:Call-Control-N 22/39 N10 */
3780			unx_drop_party_ack(c, msg, u, 1);
3781			break;
3782
3783		  default:
3784			/* Q.2971 10.5 4th paragraph */
3785			unx_drop_party_ack(c, msg, u, 0);
3786			break;
3787		}
3788		break;
3789
3790	  case SIGC_COBISETUP:	/* XXX */
3791		unx_unknown(c, msg, u);
3792		break;
3793
3794	  /*
3795	   * User signals
3796	   */
3797	  case SIGC_SETUP_request:
3798		if (c->cstate == CALLST_NULL) {
3799			/* Q.2971:Call-Control-U 4/39 (U0) */
3800			/* Q.2971:Call-Control-N 4/39 (N0) */
3801			if (c->uni->proto == UNIPROTO_UNI40N)
3802				un0_setup_request(c, msg, cookie, CALLST_N6);
3803			else
3804				un0_setup_request(c, msg, cookie, CALLST_U1);
3805			break;
3806		}
3807		VERBOSE(c->uni, UNI_FAC_ERR, 1, "setup.request in cs=%s",
3808		    callstates[c->cstate].name);
3809		uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
3810		uni_msg_destroy(msg);
3811		break;
3812
3813	  case SIGC_SETUP_response:
3814		if (c->cstate == CALLST_U6 || c->cstate == CALLST_U9 ||
3815		    c->cstate == CALLST_U7) {
3816			/* Q.2971:Call-Control-U 13/39	(U6) */
3817			/* Q.2971:Call-Control-U 14/39	(U7) */
3818			/* Q.2971:Call-Control-U 17/39	(U9) */
3819			unx_setup_response(c, msg, cookie, CALLST_U8);
3820			break;
3821		}
3822		if (c->cstate == CALLST_N1 || c->cstate == CALLST_N3 ||
3823		    c->cstate == CALLST_N4) {
3824			/* Q.2971:Call-Control-N 39/39  (N1) */
3825			/* Q.2971:Call-Control-N 7/39   (N3) */
3826			/* Q.2971:Call-Control-N 8/39   (N4) */
3827			unx_setup_response(c, msg, cookie, CALLST_N10);
3828			break;
3829		}
3830		VERBOSE(c->uni, UNI_FAC_ERR, 1, "setup.response in cs=%s",
3831		    callstates[c->cstate].name);
3832		uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
3833		uni_msg_destroy(msg);
3834		break;
3835
3836	  case SIGC_SETUP_COMPLETE_request:
3837		if (c->cstate == CALLST_N8) {
3838			/* Q.2971:Call-Control-N 15/39 (N8) */
3839			n8_setup_compl_request(c, msg, cookie, CALLST_N10);
3840			break;
3841		}
3842		VERBOSE(c->uni, UNI_FAC_ERR, 1, "setup_compl.request in cs=%s",
3843		    callstates[c->cstate].name);
3844		uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
3845		uni_msg_destroy(msg);
3846		break;
3847
3848	  case SIGC_PROCEEDING_request:
3849		if (c->cstate == CALLST_U6) {
3850			/* Q.2971:Call-Control-U 12/39 (U6) */
3851			u6n1_proceeding_request(c, msg, cookie, CALLST_U9);
3852			break;
3853		}
3854		if (c->cstate == CALLST_N1) {
3855			/* Q.2971:Call-Control-N 6/39 (N1) */
3856			u6n1_proceeding_request(c, msg, cookie, CALLST_N3);
3857			break;
3858		}
3859		VERBOSE(c->uni, UNI_FAC_ERR, 1, "proceeding.request in cs=%s",
3860		    callstates[c->cstate].name);
3861		uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
3862		uni_msg_destroy(msg);
3863		break;
3864
3865	  case SIGC_ALERTING_request:
3866		if (c->cstate == CALLST_U6 || c->cstate == CALLST_U9) {
3867			/* Q.2971:Call-Control-U 13/39 (U6) */
3868			/* Q.2971:Call-Control-U 17/39 (U9) */
3869			unx_alerting_request(c, msg, cookie, CALLST_U7);
3870			break;
3871		}
3872		if (c->cstate == CALLST_N1 || c->cstate == CALLST_N3) {
3873			/* Q.2971:Call-Control-N 38/39 (N1) */
3874			/* Q.2971:Call-Control-N 7/39  (N3) */
3875			unx_alerting_request(c, msg, cookie, CALLST_N4);
3876			break;
3877		}
3878		VERBOSE(c->uni, UNI_FAC_ERR, 1, "alerting.request in cs=%s",
3879		    callstates[c->cstate].name);
3880		uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
3881		uni_msg_destroy(msg);
3882		break;
3883
3884	  case SIGC_RELEASE_request:
3885		switch (c->cstate) {
3886
3887		  case CALLST_U1:
3888		  case CALLST_U3:
3889		  case CALLST_U4:
3890		  case CALLST_U6:
3891		  case CALLST_U7:
3892		  case CALLST_U8:
3893		  case CALLST_U9:
3894		  case CALLST_U10:
3895			/* Q.2971:Call-Control-U 27/39 */
3896			unx_release_request(c, msg, cookie, CALLST_U11);
3897			break;
3898
3899		  case CALLST_N1:
3900		  case CALLST_N3:
3901		  case CALLST_N4:
3902		  case CALLST_N6:
3903		  case CALLST_N7:
3904		  case CALLST_N8:
3905		  case CALLST_N9:
3906		  case CALLST_N10:
3907			/* Q.2971:Call-Control-N 28/39 */
3908			unx_release_request(c, msg, cookie, CALLST_N12);
3909			break;
3910
3911		  case CALLST_U11:
3912		  case CALLST_U12:
3913		  case CALLST_N11:
3914		  case CALLST_N12:
3915		  case CALLST_NULL:
3916			VERBOSE(c->uni, UNI_FAC_ERR, 1,
3917			    "release.request in cs=%s",
3918			    callstates[c->cstate].name);
3919			uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE,
3920			    cookie);
3921			uni_msg_destroy(msg);
3922			break;
3923		}
3924		break;
3925
3926	  case SIGC_RELEASE_response:
3927		if (c->cstate == CALLST_U6 || c->cstate == CALLST_U12 ||
3928		    c->cstate == CALLST_N1 || c->cstate == CALLST_N11) {
3929			/* Q.2971:Call-Control-U 12/39 (U6) */
3930			/* Q.2971:Call-Control-U 30/39 (U12) */
3931			/* Q.2971:Call-Control-N 6/39  (N1) */
3932			/* Q.2971:Call-Control-N 29/39 (N11) */
3933			unx_release_response(c, msg, cookie);
3934			break;
3935		}
3936		VERBOSE(c->uni, UNI_FAC_ERR, 1, "release.response in cs=%s",
3937		    callstates[c->cstate].name);
3938		uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
3939		uni_msg_destroy(msg);
3940		break;
3941
3942	  case SIGC_NOTIFY_request:
3943		/* Q.2971:Call-Control-U 18/39 */
3944		/* Q.2971:Call-Control-N 19/39 */
3945		unx_notify_request(c, msg, cookie);
3946		break;
3947
3948	  case SIGC_STATUS_ENQUIRY_request:
3949		/* Q.2971:Call-Control-U 31/39 */
3950		/* Q.2971:Call-Control-N 32/39 */
3951		unx_status_enquiry_request(c, msg, cookie);
3952		break;
3953
3954	  case SIGC_ADD_PARTY_request:
3955		if (c->cstate == CALLST_U4 || c->cstate == CALLST_U10 ||
3956		    c->cstate == CALLST_N7 || c->cstate == CALLST_N10) {
3957			/* Q.2971:Call-Control-U 9-10/39 (U4) */
3958			/* Q.2971:Call-Control-U 21/39 (U10) */
3959			/* Q.2971:Call-Control-N 12/39 (N7) */
3960			/* Q.2971:Call-Control-N 22/39 (N10) */
3961			unx_add_party_request(c, msg, cookie);
3962			break;
3963		}
3964		VERBOSE(c->uni, UNI_FAC_ERR, 1, "add-party.request in cs=%s",
3965		    callstates[c->cstate].name);
3966		uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
3967		uni_msg_destroy(msg);
3968		break;
3969
3970	  case SIGC_PARTY_ALERTING_request:
3971		if (c->cstate == CALLST_U7 || c->cstate == CALLST_U8 ||
3972		    c->cstate == CALLST_U10 ||
3973		    c->cstate == CALLST_N4 || c->cstate == CALLST_N10) {
3974			/* Q.2971:Call-Control-U 14/39 U7 */
3975			/* Q.2971:Call-Control-U 15/39 U8 */
3976			/* Q.2971:Call-Control-U 21/39 U10 */
3977			/* Q.2971:Call-Control-N 8/39  N4 */
3978			/* Q.2971:Call-Control-N 22/39 N10 */
3979			unx_party_alerting_request(c, msg, cookie);
3980			break;
3981		}
3982		VERBOSE(c->uni, UNI_FAC_ERR, 1,
3983		    "party-alerting.request in cs=%s",
3984		    callstates[c->cstate].name);
3985		uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
3986		uni_msg_destroy(msg);
3987		break;
3988
3989	  case SIGC_ADD_PARTY_ACK_request:
3990		if (c->cstate == CALLST_U10 || c->cstate == CALLST_N10) {
3991			/* Q.2971:Call-Control-U 21/39 (U10) */
3992			/* Q.2971:Call-Control-N 22/39 (N10)*/
3993			un10_add_party_ack_request(c, msg, cookie);
3994			break;
3995		}
3996		VERBOSE(c->uni, UNI_FAC_ERR, 1,
3997		    "add-party-ack.request in cs=%s",
3998		    callstates[c->cstate].name);
3999		uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
4000		uni_msg_destroy(msg);
4001		break;
4002
4003	  case SIGC_ADD_PARTY_REJ_request:
4004		if (c->cstate == CALLST_U7 || c->cstate == CALLST_U8 ||
4005		    c->cstate == CALLST_U10 ||
4006		    c->cstate == CALLST_N4 || c->cstate == CALLST_N10) {
4007			/* Q.2971:Call-Control-U 14/39 U7 */
4008			/* Q.2971:Call-Control-U 15/39 U8 */
4009			/* Q.2971:Call-Control-U 21/39 U10 */
4010			/* Q.2971:Call-Control-N 8/39  N4 */
4011			/* Q.2971:Call-Control-N 22/39 N10 */
4012			unx_add_party_rej_request(c, msg, cookie);
4013			break;
4014		}
4015		VERBOSE(c->uni, UNI_FAC_ERR, 1,
4016		    "add-party-rej.request in cs=%s",
4017		    callstates[c->cstate].name);
4018		uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
4019		uni_msg_destroy(msg);
4020		break;
4021
4022	  case SIGC_DROP_PARTY_request:
4023		if (c->cstate != CALLST_U11 && c->cstate != CALLST_U12 &&
4024		    c->cstate != CALLST_N11 && c->cstate != CALLST_N12 &&
4025		    c->cstate != CALLST_NULL) {
4026			/* Q.2971:Call-Control-U 21/39 U10 */
4027			/* Q.2971:Call-Control-U 26/39 U1-U9 */
4028			/* Q.2971:Call-Control-N 22/39 N10 */
4029			/* Q.2971:Call-Control-N 27/39 N1-N9 */
4030			unx_drop_party_request(c, msg, cookie);
4031			break;
4032		}
4033		VERBOSE(c->uni, UNI_FAC_ERR, 1, "drop-party.request in cs=%s",
4034		    callstates[c->cstate].name);
4035		uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
4036		uni_msg_destroy(msg);
4037		break;
4038
4039	  case SIGC_DROP_PARTY_ACK_request:
4040		if (c->cstate != CALLST_U11 && c->cstate != CALLST_U12 &&
4041		    c->cstate != CALLST_N11 && c->cstate != CALLST_N12 &&
4042		    c->cstate != CALLST_NULL) {
4043			/* Q.2971:Call-Control-U 21/39 U10 */
4044			/* Q.2971:Call-Control-U 26/39 U1-U9 */
4045			/* Q.2971:Call-Control-N 22/39 N10 */
4046			/* Q.2971:Call-Control-N 27/39 N1-N9 */
4047			unx_drop_party_ack_request(c, msg, cookie);
4048			break;
4049		}
4050		VERBOSE(c->uni, UNI_FAC_ERR, 1,
4051		    "drop-party-ack.request in cs=%s",
4052		    callstates[c->cstate].name);
4053		uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
4054		uni_msg_destroy(msg);
4055		break;
4056
4057	  case SIGC_ABORT_CALL_request:
4058	    {
4059		struct uni *uni = c->uni;
4060
4061		uni_destroy_call(c, 0);
4062		uniapi_uni_error(uni, UNIAPI_OK, cookie, UNI_CALLSTATE_U0);
4063		break;
4064	    }
4065
4066	  /*
4067	   * Timers
4068	   */
4069	  case SIGC_T301:
4070		if (c->cstate == CALLST_U4 || c->cstate == CALLST_N7) {
4071			/* Q.2971:Call-Control-U Missing */
4072			/* Q.2971:Call-Control-N 14/39 */
4073			u4n7_t301(c);
4074			break;
4075		}
4076		VERBOSE(c->uni, UNI_FAC_ERR, 1, "T301 in cs=%s",
4077		    callstates[c->cstate].name);
4078		break;
4079
4080	  case SIGC_T303:
4081		if (c->cstate == CALLST_U1 || c->cstate == CALLST_N6) {
4082			/* Q.2971:Call-Control-U 6/39 */
4083			/* Q.2971:Call-Control-N 11/39 */
4084			u1n6_t303(c);
4085			break;
4086		}
4087		VERBOSE(c->uni, UNI_FAC_ERR, 1, "T303 in cs=%s",
4088		    callstates[c->cstate].name);
4089		break;
4090
4091	  case SIGC_T308:
4092		if (c->cstate == CALLST_U11 || c->cstate == CALLST_N12) {
4093			/* Q.2971:Call-Control-U 28/39 */
4094			/* Q.2971:Call-Control-N 30/39 */
4095			u11n12_t308(c);
4096			break;
4097		}
4098		VERBOSE(c->uni, UNI_FAC_ERR, 1, "T308 in cs=%s",
4099		    callstates[c->cstate].name);
4100		break;
4101
4102	  case SIGC_T310:
4103		if (c->cstate == CALLST_U3 || c->cstate == CALLST_N9) {
4104			/* Q.2971:Call-Control-U 7/39 */
4105			/* Q.2971:Call-Control-N 17/39 */
4106			u3n9_t310(c);
4107			break;
4108		}
4109		VERBOSE(c->uni, UNI_FAC_ERR, 1, "T310 in cs=%s",
4110		    callstates[c->cstate].name);
4111		break;
4112
4113	  case SIGC_T313:
4114		if (c->cstate == CALLST_U8) {
4115			/* Q.2971:Call-Control-U 15/39 */
4116			u8_t313(c);
4117			break;
4118		}
4119		VERBOSE(c->uni, UNI_FAC_ERR, 1, "T313 in cs=%s",
4120		    callstates[c->cstate].name);
4121		break;
4122
4123	  case SIGC_T322:
4124		/* Q.2971:Call-Control-U 34/39 */
4125		/* Q.2971:Call-Control-N 35/39 */
4126		unx_t322(c);
4127		break;
4128
4129	  case SIGC_CALL_DELETE:
4130		CALL_FREE(c);
4131		break;
4132
4133	  /*
4134	   * Party-Control
4135	   */
4136	  case SIGC_DROP_PARTY_indication:
4137		if (c->uni->proto == UNIPROTO_UNI40U)
4138			/* Q.2971:Call-Control-U 23/39 */
4139			ux_drop_party_indication(c, msg);
4140		else
4141			/* Q.2971:Call-Control-N 23/39 */
4142			nx_drop_party_indication(c, msg);
4143		break;
4144
4145	  case SIGC_DROP_PARTY_ACK_indication:
4146		if (c->uni->proto == UNIPROTO_UNI40U)
4147			/* Q.2971:Call-Control-U 23/39 */
4148			ux_drop_party_ack_indication(c, msg);
4149		else
4150			/* Q.2971:Call-Control-N 23/39 */
4151			nx_drop_party_ack_indication(c, msg);
4152		break;
4153
4154	  case SIGC_ADD_PARTY_REJ_indication:
4155		if (c->uni->proto == UNIPROTO_UNI40U)
4156			/* Q.2971:Call-Control-U 23/39 */
4157			ux_add_party_rej_indication(c, msg);
4158		else
4159			/* Q.2971:Call-Control-N 23/39 */
4160			nx_add_party_rej_indication(c, msg);
4161		break;
4162
4163
4164	  case SIGC_SEND_DROP_PARTY:
4165		/* Q.2971:Call-Control-U 21/39 */
4166		/* Q.2971:Call-Control-U 25/39 */
4167		if (uni_party_act_count(c, 2) != 0)
4168			(void)uni_send_output(u, c->uni);
4169		else if(c->cstate != CALLST_U11) {
4170			c->uni->cause = u->u.drop_party.cause;
4171			clear_callD(c);
4172		}
4173		UNI_FREE(u);
4174		break;
4175
4176	  case SIGC_SEND_DROP_PARTY_ACK:
4177		/* Q.2971:Call-Control-U 21/39 */
4178		/* Q.2971:Call-Control-U 25/39 */
4179		if (uni_party_act_count(c, 2) != 0)
4180			(void)uni_send_output(u, c->uni);
4181		else if (c->cstate != CALLST_U11) {
4182			c->uni->cause = u->u.drop_party_ack.cause;
4183			clear_callD(c);
4184		}
4185		UNI_FREE(u);
4186		break;
4187
4188	  case SIGC_SEND_ADD_PARTY_REJ:
4189		/* Q.2971:Call-Control-U 21/39 */
4190		/* Q.2971:Call-Control-U 24/39 */
4191		unx_send_add_party_rej(c, u);
4192		break;
4193
4194	  case SIGC_SEND_STATUS_ENQ:
4195		/* Q.2971:Call-Control-U 21/39 */
4196		/* Q.2971:Call-Control-U 25/39 */
4197		unx_send_party_status_enq(c, u);
4198		break;
4199
4200	  case SIGC_PARTY_DESTROYED:
4201		c->uni->funcs->uni_output(c->uni, c->uni->arg,
4202		    UNIAPI_PARTY_DESTROYED, cookie, msg);
4203		break;
4204
4205	  case SIGC_END:
4206		break;
4207	}
4208
4209	return;
4210
4211  drop:
4212	/*
4213	 * This is for SAAL message signals that should be dropped.
4214	 */
4215	uni_msg_destroy(msg);
4216	UNI_FREE(u);
4217}
4218
4219/**********************************************************************/
4220
4221/*
4222 * Timeout functions
4223 */
4224static void
4225t308_func(struct call *c)
4226{
4227	uni_enq_call(c, SIGC_T308, 0, NULL, NULL);
4228}
4229static void
4230t303_func(struct call *c)
4231{
4232	uni_enq_call(c, SIGC_T303, 0, NULL, NULL);
4233}
4234static void
4235t301_func(struct call *c)
4236{
4237	uni_enq_call(c, SIGC_T301, 0, NULL, NULL);
4238}
4239static void
4240t310_func(struct call *c)
4241{
4242	uni_enq_call(c, SIGC_T310, 0, NULL, NULL);
4243}
4244static void
4245t313_func(struct call *c)
4246{
4247	uni_enq_call(c, SIGC_T313, 0, NULL, NULL);
4248}
4249
4250static void
4251t322_func(struct call *c)
4252{
4253	uni_enq_call(c, SIGC_T322, 0, NULL, NULL);
4254}
4255
4256/**********************************************************************/
4257
4258/*
4259 * Check whether the peer state is compatible with our state.
4260 * Return the new callstate we should go to (either U0 or the current
4261 * state).
4262 * None of the state is U0 here. My state is not U11 or U12.
4263 *
4264 * Well, this turns out to be not so easy: the status enquiry could have
4265 * been sent before we changed into the current state - the status will
4266 * report a previous state without anything been lost.
4267 *
4268 * Incoming states are incompatible with outgoing states. Everything is ok.
4269 */
4270static enum call_state
4271state_compat(struct call *c, enum uni_callstate peer)
4272{
4273	if ((c->cstate == CALLST_U1 ||
4274	     c->cstate == CALLST_U3 ||
4275	     c->cstate == CALLST_U4) &&
4276	   (peer == UNI_CALLSTATE_N6 ||
4277	    peer == UNI_CALLSTATE_N7 ||
4278	    peer == UNI_CALLSTATE_N8 ||
4279	    peer == UNI_CALLSTATE_N9))
4280		return (CALLST_NULL);
4281
4282	if ((c->cstate == CALLST_N6 ||
4283	     c->cstate == CALLST_N7 ||
4284	     c->cstate == CALLST_N8 ||
4285	     c->cstate == CALLST_N9) &&
4286	    (peer == UNI_CALLSTATE_U1 ||
4287	     peer == UNI_CALLSTATE_U3 ||
4288	     peer == UNI_CALLSTATE_U4))
4289		return (CALLST_NULL);
4290
4291	if ((peer == UNI_CALLSTATE_N1 ||
4292	     peer == UNI_CALLSTATE_N3 ||
4293	     peer == UNI_CALLSTATE_N4) &&
4294	   (c->cstate == CALLST_U6 ||
4295	    c->cstate == CALLST_U7 ||
4296	    c->cstate == CALLST_U8 ||
4297	    c->cstate == CALLST_N9))
4298		return (CALLST_NULL);
4299
4300	if ((peer == UNI_CALLSTATE_U6 ||
4301	     peer == UNI_CALLSTATE_U7 ||
4302	     peer == UNI_CALLSTATE_U8 ||
4303	     peer == UNI_CALLSTATE_U9) &&
4304	   (c->cstate == CALLST_N1 ||
4305	    c->cstate == CALLST_N3 ||
4306	    c->cstate == CALLST_N4))
4307		return (CALLST_NULL);
4308
4309	return (c->cstate);
4310}
4311