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_coord.c,v 1.12 2004/08/05 07:11:01 brandt Exp $
30 *
31 * Coordinator
32 */
33
34#include <netnatm/unimsg.h>
35#include <netnatm/saal/sscfudef.h>
36#include <netnatm/msg/unistruct.h>
37#include <netnatm/msg/unimsglib.h>
38#include <netnatm/sig/uni.h>
39
40#include <netnatm/sig/unipriv.h>
41#include <netnatm/sig/unimkmsg.h>
42
43#define STR(S) [S] = #S
44static const char *const cunames[] = {
45	STR(CU_STAT0),
46	STR(CU_STAT1),
47	STR(CU_STAT2),
48	STR(CU_STAT3),
49};
50
51#define DEF_PRIV_SIG(NAME, FROM)	[SIG##NAME] =	"SIG"#NAME,
52static const char *const coord_sigs[] = {
53	DEF_COORD_SIGS
54};
55#undef DEF_PRIV_SIG
56
57static void sig_all_calls(struct uni *, u_int sig);
58static void set_custat(struct uni *, enum cu_stat);
59
60static void input_dummy(struct uni *uni, struct uni_msg *m, struct uni_all *u);
61static void input_global(struct uni *uni, struct uni_msg *m, struct uni_all *u);
62static void input_unknown(struct uni *uni, struct uni_msg *m, struct uni_all *u);
63static void input_cobi(struct call *c, struct uni_msg *m, struct uni_all *u);
64static void input_call(struct call *c, struct uni_msg *m, struct uni_all *u);
65
66TIMER_FUNC_UNI(t309, t309_func)
67
68/*
69 * All those 'bogus signal' printouts are not specified in the SDLs.
70 */
71
72
73/*
74 * SAAL-ESTABLISH.indication
75 *
76 * This means either a resynchronisation or error-recovery or
77 * an incoming SSCOP connection.
78 */
79static void
80coord_saal_establish_indication(struct uni *uni)
81{
82	switch (uni->custat) {
83
84	  case CU_STAT0:	/* Q.2931:Coord-U 4/10 */
85	  case CU_STAT3:	/* Q.2931:Coord-U 5/10 */
86		sig_all_calls(uni, SIGC_LINK_ESTABLISH_indication);
87		set_custat(uni, CU_STAT3);
88		break;
89
90	  case CU_STAT1:
91	  case CU_STAT2:
92		VERBOSE0(uni, UNI_FAC_COORD,
93		    "signal saal_establish.indication in CU%u", uni->custat);
94		break;
95
96	  default:
97		ASSERT(0, ("CU_STAT*"));
98	}
99}
100
101/*
102 * SAAL-ESTABLISH.confirm
103 */
104static void
105coord_saal_establish_confirm(struct uni *uni)
106{
107	switch (uni->custat) {
108
109	  case CU_STAT0:
110	  case CU_STAT2:
111		VERBOSE0(uni, UNI_FAC_COORD,
112		    "signal saal_establish.confirm in CU%u", uni->custat);
113		break;
114
115	  case CU_STAT1:
116		/*
117		 * Q.2931:Co-ord-U 4/10
118		 */
119		TIMER_STOP_UNI(uni, t309);
120		sig_all_calls(uni, SIGC_LINK_ESTABLISH_confirm);
121		uni->funcs->uni_output(uni, uni->arg,
122		    UNIAPI_LINK_ESTABLISH_confirm, 0, NULL);
123		set_custat(uni, CU_STAT3);
124		break;
125
126	  case CU_STAT3:
127		/*
128		 * Q.2931:Coord-U 5/10
129		 */
130		sig_all_calls(uni, SIGC_LINK_ESTABLISH_confirm);
131		uni->funcs->uni_output(uni, uni->arg,
132		    UNIAPI_LINK_ESTABLISH_confirm, 0, NULL);
133		break;
134
135	  default:
136		ASSERT(0, ("CU_STAT*"));
137	}
138}
139
140/*
141 * SAAL-RELEASE.confirm
142 */
143static void
144coord_saal_release_confirm(struct uni *uni)
145{
146	switch (uni->custat) {
147
148	  case CU_STAT0:
149	  case CU_STAT1:
150	  case CU_STAT3:
151		VERBOSE0(uni, UNI_FAC_COORD,
152		    "signal saal_release.confirm in CU%u", uni->custat);
153		break;
154
155	  case CU_STAT2:
156		/*
157		 * Q.2931:Coord-U 5/10
158		 */
159		uni->funcs->uni_output(uni, uni->arg,
160		    UNIAPI_LINK_RELEASE_confirm, 0, NULL);
161		set_custat(uni, CU_STAT0);
162		break;
163
164	  default:
165		ASSERT(0, ("CU_STAT*"));
166	}
167}
168
169/*
170 * SAAL failure.
171 */
172static void
173coord_saal_release_indication(struct uni *uni)
174{
175	switch (uni->custat) {
176
177	  case CU_STAT0:
178	  case CU_STAT2:
179		VERBOSE0(uni, UNI_FAC_COORD,
180		    "signal saal_release.indication in CU%u", uni->custat);
181		break;
182
183	  case CU_STAT1:
184	  case CU_STAT3:
185		/*
186		 * Q.2931:Coord-U 4/10
187		 * Q.2931:Coord-U 5/10
188		 */
189		sig_all_calls(uni, SIGC_LINK_RELEASE_indication);
190		set_custat(uni, CU_STAT0);
191		break;
192
193	  default:
194		ASSERT(0, ("CU_STAT*"));
195	}
196}
197
198/*
199 * Link-establish.request from USER. This can also come from
200 * a call instance. In this case 'cookie' is zero.
201 */
202static void
203coord_link_establish_request(struct uni *uni, uint32_t cookie)
204{
205	switch (uni->custat) {
206
207	  case CU_STAT0:
208		/*
209		 * Q.2931:Coord-U 4/10
210		 */
211		uni->funcs->saal_output(uni, uni->arg,
212		    SAAL_ESTABLISH_request, NULL);
213		if (!TIMER_ISACT(uni, t309))
214			TIMER_START_UNI(uni, t309, uni->timer309);
215		set_custat(uni, CU_STAT1);
216		if (cookie)
217			uniapi_uni_error(uni, UNIAPI_OK, cookie, 0);
218		break;
219
220	  case CU_STAT1:
221		/*
222		 * Q.2931:Coord-U 4/10
223		 * This is probably missing from the delay field.
224		 */
225		uni_delenq_coord(uni, SIGO_LINK_ESTABLISH_request,
226		    cookie, NULL);
227		break;
228
229	  case CU_STAT2:
230		uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0);
231		if (cookie == 0)
232			VERBOSE0(uni, UNI_FAC_COORD,
233			    "signal link-establish.request in CU%u",
234			    uni->custat);
235		break;
236
237	  case CU_STAT3:
238		/*
239		 * Q.2931:Coord-U 5/10
240		 */
241		uni->funcs->uni_output(uni, uni->arg,
242		    UNIAPI_LINK_ESTABLISH_confirm, 0, NULL);
243		uniapi_uni_error(uni, UNIAPI_OK, cookie, 0);
244		break;
245
246	  default:
247		ASSERT(0, ("CU_STAT*"));
248	}
249}
250
251/*
252 * Link-release.request from user
253 */
254static void
255coord_link_release_request(struct uni *uni, u_int cookie)
256{
257	switch (uni->custat) {
258
259	  case CU_STAT0:
260	  case CU_STAT1:
261	  case CU_STAT2:
262		uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0);
263		break;
264
265	  case CU_STAT3:
266		/*
267		 * Q.2931:Coord-U 5/10
268		 */
269		uni->funcs->saal_output(uni, uni->arg,
270		    SAAL_RELEASE_request, NULL);
271		set_custat(uni, CU_STAT2);
272		uniapi_uni_error(uni, UNIAPI_OK, cookie, 0);
273		break;
274
275	  default:
276		ASSERT(0, ("CU_STAT*"));
277	}
278}
279
280/*
281 * T309 timeout signal
282 */
283static void
284coord_t309(struct uni *uni)
285{
286	switch (uni->custat) {
287
288	  case CU_STAT0:
289	  case CU_STAT1:
290		/*
291		 * Q.2931:Coord-U 4/10
292		 */
293		sig_all_calls(uni, SIGC_LINK_ESTABLISH_ERROR_indication);
294		set_custat(uni, CU_STAT0);
295		/* this is not in the SDLs, but how will the call control
296		 * know, that starting the LINK has failed otherwise? */
297		uni->funcs->uni_output(uni, uni->arg,
298		    UNIAPI_LINK_RELEASE_confirm, 0, NULL);
299		break;
300
301	  case CU_STAT2:
302	  case CU_STAT3:
303		VERBOSE0(uni, UNI_FAC_COORD,
304		    "signal T309 in CU%u", uni->custat);
305		break;
306
307	  default:
308		ASSERT(0, ("CU_STAT*"));
309	}
310}
311
312/*
313 * Message from SAAL
314 */
315static void
316coord_saal_data_indication(struct uni *uni, struct uni_msg *m)
317{
318	struct uni_all *u;
319	struct call *c;
320
321	memset(&uni->cause, 0, sizeof(uni->cause));
322	if ((u = UNI_ALLOC()) == NULL) {
323		uni_msg_destroy(m);
324		return;
325	}
326	if (uni_decode_head(m, u, &uni->cx)) {
327		VERBOSE(uni, UNI_FAC_COORD, 2, "bogus message - ignored");
328		uni_msg_destroy(m);
329		UNI_FREE(u);
330		return;
331	}
332	if (u->u.hdr.cref.cref == CREF_DUMMY) {
333		if (uni->cx.q2932) {
334			input_dummy(uni, m, u);
335		} else {
336			VERBOSE(uni, UNI_FAC_COORD, 2, "dummy cref - ignored");
337			UNI_FREE(u);
338			uni_msg_destroy(m);
339		}
340		return;
341	}
342
343	if (u->u.hdr.cref.cref == CREF_GLOBAL)
344		input_global(uni, m, u);
345	else if ((c = uni_find_call(uni, &u->u.hdr.cref)) == NULL)
346		input_unknown(uni, m, u);
347	else if (c->type == CALL_COBI)
348		input_cobi(c, m, u);
349	else
350		input_call(c, m, u);
351}
352
353/*
354 * Message with global call reference
355 *
356 * Q.2931:Coord-U (X) 7/10
357 */
358static void
359input_global(struct uni *uni, struct uni_msg *m, struct uni_all *u)
360{
361	VERBOSE(uni, UNI_FAC_COORD, 2, "GLOB MTYPE = %x", u->mtype);
362
363	switch (u->mtype) {
364
365	  default:
366		/*
367		 * Q.2931:Coord-U 7/10
368		 * Q.2931: 5.6.3.2e
369		 * Amd4:   29e
370		 */
371		uni_respond_status(uni, &u->u.hdr.cref,
372		    u->u.hdr.cref.flag ? uni->glob_start : uni->glob_respond,
373		    UNI_CAUSE_CREF_INV);
374		break;
375
376	  case UNI_RESTART:
377		if (u->u.hdr.cref.flag) {
378			/*
379			 * Q.2931:Coord-U 7/10 (5.6.3.2h)
380			 */
381			uni_respond_status(uni, &u->u.hdr.cref,
382			    uni->glob_start, UNI_CAUSE_CREF_INV);
383			break;
384		}
385		uni_enq_resp(uni, SIGR_RESTART, 0, m, u);
386		return;
387
388	  case UNI_RESTART_ACK:
389		if (!u->u.hdr.cref.flag) {
390			/*
391			 * Q.2931:Coord-U 7/10 (5.6.3.2h)
392			 * Note, that the SDL diagram contains an error.
393			 * The error with the 'YES' label should go to the
394			 * box below 'OTHER'.
395			 */
396			uni_respond_status(uni, &u->u.hdr.cref,
397			    uni->glob_respond, UNI_CAUSE_CREF_INV);
398			break;
399		}
400		uni_enq_start(uni, SIGS_RESTART_ACK, 0, m, u);
401		return;
402
403	  case UNI_STATUS:
404		if (u->u.hdr.cref.flag)
405			uni_enq_start(uni, SIGS_STATUS, 0, m, u);
406		else
407			uni_enq_resp(uni, SIGR_STATUS, 0, m, u);
408		return;
409	}
410	uni_msg_destroy(m);
411	UNI_FREE(u);
412}
413
414/*
415 * Q.2931:Coord-U 8/10
416 *
417 * Message for an unknown call reference
418 */
419static void
420input_unknown(struct uni *uni, struct uni_msg *m, struct uni_all *u)
421{
422	struct uni_all *resp;
423	struct call *c;
424	u_int cause = UNI_CAUSE_CREF_INV;
425
426	VERBOSE(uni, UNI_FAC_COORD, 2, "UNKNOWN MTYPE = %x", u->mtype);
427
428	switch (u->mtype) {
429
430	  default:
431		/*
432		 * This message type is entirly unknown
433		 *
434		 * 5.6.4 and 5.7.1 are only when the call is not in the
435		 * NULL state. This means, 5.6.3.2a takes over.
436		 */
437		break;
438
439	  case UNI_SETUP:
440		if (u->u.hdr.cref.flag)
441			/*
442			 * 5.6.3.2c
443			 */
444			goto drop;
445		if ((c = uni_create_call(uni, u->u.hdr.cref.cref, 0, 0)) != NULL) {
446			uni_enq_call(c, SIGC_SETUP, 0, m, u);
447			return;
448		}
449		goto drop;
450
451	  case UNI_RELEASE_COMPL:
452		/*
453		 * 5.6.3.2c
454		 */
455		goto drop;
456
457	  case UNI_STATUS:
458		/*
459		 * 5.6.12
460		 *
461		 * The SDLs don't use the verify procedure and don't
462		 * handle the case of an invalid callstate - we
463		 * ignore the message, if the callstate is not good.
464		 */
465		(void)uni_decode_body(m, u, &uni->cx);
466		if (!IE_ISGOOD(u->u.status.callstate))
467			goto drop;
468		if (u->u.status.callstate.state == UNI_CALLSTATE_U0)
469			goto drop;
470		cause = UNI_CAUSE_MSG_INCOMP;
471		break;
472
473	  case UNI_STATUS_ENQ:
474		if ((resp = UNI_ALLOC()) == NULL)
475			goto drop;
476
477		(void)uni_decode_body(m, u, &uni->cx);
478		MK_MSG_RESP(resp, UNI_STATUS, &u->u.hdr.cref);
479		MK_IE_CALLSTATE(resp->u.status.callstate, UNI_CALLSTATE_U0);
480		MK_IE_CAUSE(resp->u.status.cause, UNI_CAUSE_LOC_USER,
481		    UNI_CAUSE_STATUS);
482
483		if (IE_ISGOOD(u->u.status_enq.epref)) {
484			/* reflect epref as required by L3MU_PO */
485			resp->u.status.epref = u->u.status_enq.epref;
486			MK_IE_EPREF(resp->u.status.epref,
487			    u->u.status_enq.epref.epref,
488			    !u->u.status_enq.epref.flag);
489			MK_IE_EPSTATE(resp->u.status.epstate, UNI_EPSTATE_NULL);
490		}
491
492		(void)uni_send_output(resp, uni);
493
494		UNI_FREE(resp);
495		goto drop;
496
497	  case UNI_COBISETUP:
498		if (u->u.hdr.cref.flag)
499			/*
500			 * 5.6.3.2c (probably)
501			 */
502			goto drop;
503		if ((c = uni_create_call(uni, u->u.hdr.cref.cref, 0, 0)) != NULL) {
504			uni_enq_call(c, SIGC_COBISETUP, 0, m, u);
505			return;
506		}
507		goto drop;
508	}
509
510	/*
511	 * 5.6.3.2a)
512	 *
513	 * Respond with a RELEASE COMPLETE
514	 */
515	if ((resp = UNI_ALLOC()) == NULL)
516		goto drop;
517
518	MK_MSG_RESP(resp, UNI_RELEASE_COMPL, &u->u.hdr.cref);
519	MK_IE_CAUSE(resp->u.release_compl.cause[0], UNI_CAUSE_LOC_USER, cause);
520	if (uni_diag(cause, UNI_CODING_ITU) == UNI_DIAG_MTYPE)
521		ADD_CAUSE_MTYPE(resp->u.release_compl.cause[0], u->mtype);
522
523	(void)uni_send_output(resp, uni);
524
525	UNI_FREE(resp);
526
527  drop:
528	UNI_FREE(u);
529	uni_msg_destroy(m);
530}
531
532static void
533input_cobi(struct call *c __unused, struct uni_msg *m, struct uni_all *u)
534{
535	/* XXX */
536	UNI_FREE(u);
537	uni_msg_destroy(m);
538}
539
540static void
541input_dummy(struct uni *uni __unused, struct uni_msg *m, struct uni_all *u)
542{
543	/* XXX */
544	UNI_FREE(u);
545	uni_msg_destroy(m);
546}
547
548static void
549input_call(struct call *c, struct uni_msg *m, struct uni_all *u)
550{
551	VERBOSE(c->uni, UNI_FAC_COORD, 2, "CALL MTYPE = %x %d/%s",
552		u->mtype, c->cref, c->mine ? "mine":"his");
553
554	switch (u->mtype) {
555
556	  case UNI_SETUP:
557		/*
558		 * Ignored
559		 */
560		break;
561
562	  case UNI_CALL_PROC:
563		uni_enq_call(c, SIGC_CALL_PROC, 0, m, u);
564		return;
565
566	  case UNI_ALERTING:
567		uni_enq_call(c, SIGC_ALERTING, 0, m, u);
568		return;
569
570	  case UNI_RELEASE:
571		uni_enq_call(c, SIGC_RELEASE, 0, m, u);
572		return;
573
574	  case UNI_RELEASE_COMPL:
575		uni_enq_call(c, SIGC_RELEASE_COMPL, 0, m, u);
576		return;
577
578	  case UNI_CONNECT:
579		uni_enq_call(c, SIGC_CONNECT, 0, m, u);
580		return;
581
582	  case UNI_CONNECT_ACK:
583		uni_enq_call(c, SIGC_CONNECT_ACK, 0, m, u);
584		return;
585
586	  case UNI_NOTIFY:
587		uni_enq_call(c, SIGC_NOTIFY, 0, m, u);
588		return;
589
590	  case UNI_STATUS:
591		uni_enq_call(c, SIGC_STATUS, 0, m, u);
592		return;
593
594	  case UNI_STATUS_ENQ:
595		uni_enq_call(c, SIGC_STATUS_ENQ, 0, m, u);
596		return;
597
598	  case UNI_ADD_PARTY:
599		uni_enq_call(c, SIGC_ADD_PARTY, 0, m, u);
600		return;
601
602	  case UNI_PARTY_ALERTING:
603		uni_enq_call(c, SIGC_PARTY_ALERTING, 0, m, u);
604		return;
605
606	  case UNI_ADD_PARTY_ACK:
607		uni_enq_call(c, SIGC_ADD_PARTY_ACK, 0, m, u);
608		return;
609
610	  case UNI_ADD_PARTY_REJ:
611		uni_enq_call(c, SIGC_ADD_PARTY_REJ, 0, m, u);
612		return;
613
614	  case UNI_DROP_PARTY:
615		uni_enq_call(c, SIGC_DROP_PARTY, 0, m, u);
616		return;
617
618	  case UNI_DROP_PARTY_ACK:
619		uni_enq_call(c, SIGC_DROP_PARTY_ACK, 0, m, u);
620		return;
621
622	  default:
623		uni_enq_call(c, SIGC_UNKNOWN, 0, m, u);
624		return;
625	}
626	UNI_FREE(u);
627	uni_msg_destroy(m);
628}
629
630
631/*
632 * This macro tries to implement the delaying behaviour for
633 * message from the API when we are in the Awaiting-Establish state.
634 * In this state, the message is delayed. If we drop back to CU 0,
635 * everything gets unqueued and errors are returned for all that stuff.
636 * If we progess to CUSTAT2 we process the requests.
637 */
638#define COMMON_DELAY(SIG, COOKIE)					\
639		if (uni->custat == CU_STAT0 || uni->custat == CU_STAT2) {\
640			uniapi_uni_error(uni, UNIAPI_ERROR_BADCU,	\
641			    COOKIE, 0);					\
642			break;						\
643		}							\
644		if (uni->custat == CU_STAT1) {				\
645			uni_delenq_coord(uni, SIG, COOKIE, msg);	\
646			break;						\
647		}
648
649/*
650 * Signal handler of the coordinator
651 */
652void
653uni_sig_coord(struct uni *uni, enum coord_sig sig, uint32_t cookie,
654    struct uni_msg *msg)
655{
656	struct call *c;
657
658	if (sig >= SIGO_END) {
659		VERBOSE(uni, UNI_FAC_ERR, 1, "Signal %d outside of range to "
660		    "Coord", sig);
661		if (msg)
662			uni_msg_destroy(msg);
663		return;
664	}
665
666	VERBOSE(uni, UNI_FAC_COORD, 1, "Signal %s in state %s",
667	    coord_sigs[sig], cunames[uni->custat]);
668
669	switch (sig) {
670
671	  case SIGO_END:
672		break;
673
674	  case SIGO_DATA:	/* delayed output */
675		if (uni->custat == CU_STAT0 || uni->custat == CU_STAT1)
676			break;	/* drop */
677		if (uni->custat == CU_STAT1)
678			uni_delenq_coord(uni, SIGO_DATA, cookie, msg);/* ??? */
679		else
680			uni->funcs->saal_output(uni, uni->arg,
681			    SAAL_DATA_request, msg);
682		msg = NULL;
683		break;
684
685	  /*
686	   * SAAL signals
687	   */
688	  case SIGO_SAAL_ESTABLISH_indication:
689		coord_saal_establish_indication(uni);
690		break;
691
692	  case SIGO_SAAL_ESTABLISH_confirm:
693		coord_saal_establish_confirm(uni);
694		break;
695
696	  case SIGO_SAAL_RELEASE_confirm:
697		coord_saal_release_confirm(uni);
698		break;
699
700	  case SIGO_SAAL_RELEASE_indication:
701		coord_saal_release_indication(uni);
702		break;
703
704	  case SIGO_SAAL_DATA_indication:
705		coord_saal_data_indication(uni, msg);
706		msg = NULL;
707		break;
708
709	  case SIGO_SAAL_UDATA_indication:
710		VERBOSE0(uni, UNI_FAC_ERR, "SAAL_UDATA_indication");
711		break;
712
713	  /*
714	   * Signals from USER
715	   */
716	  case SIGO_LINK_ESTABLISH_request:
717		coord_link_establish_request(uni, cookie);
718		break;
719
720	  case SIGO_LINK_RELEASE_request:
721		coord_link_release_request(uni, cookie);
722		break;
723
724	  case SIGO_RESET_request:
725		uni_enq_start(uni, SIGS_RESET_request, cookie, msg, NULL);
726		msg = NULL;
727		if (uni->custat == CU_STAT0) {
728			uni->funcs->saal_output(uni, uni->arg,
729			    SAAL_ESTABLISH_request, NULL);
730			if (!TIMER_ISACT(uni, t309))
731				TIMER_START_UNI(uni, t309, uni->timer309);
732			set_custat(uni, CU_STAT1);
733		}
734		break;
735
736	  case SIGO_RESET_ERROR_response:
737		COMMON_DELAY(SIGO_RESET_ERROR_response, cookie);
738		uni_enq_resp(uni, SIGR_RESET_ERROR_response, cookie, msg, NULL);
739		msg = NULL;
740		break;
741
742	  case SIGO_RESET_response:
743		COMMON_DELAY(SIGO_RESET_response, cookie);
744		uni_enq_resp(uni, SIGR_RESET_response, cookie, msg, NULL);
745		msg = NULL;
746		break;
747
748	  case SIGO_SETUP_request:
749		if ((c = uni_create_new_call(uni, cookie)) != NULL) {
750			uni_enq_call(c, SIGC_SETUP_request, cookie, msg, NULL);
751			msg = NULL;
752			if (uni->custat == CU_STAT0) {
753				uni->funcs->saal_output(uni, uni->arg,
754				    SAAL_ESTABLISH_request, NULL);
755				if (!TIMER_ISACT(uni, t309))
756					TIMER_START_UNI(uni, t309, uni->timer309);
757				set_custat(uni, CU_STAT1);
758			}
759		} else {
760			uniapi_uni_error(uni, UNIAPI_ERROR_NOMEM, cookie,
761			    UNI_CALLSTATE_U0);
762		}
763		break;
764
765	  case SIGO_PROCEEDING_request:
766	    {
767		struct uniapi_proceeding_request *arg =
768		    uni_msg_rptr(msg, struct uniapi_proceeding_request *);
769
770		COMMON_DELAY(SIGO_PROCEEDING_request, cookie);
771		if ((c = uni_find_call(uni, &arg->call_proc.hdr.cref)) != NULL) {
772			uni_enq_call(c, SIGC_PROCEEDING_request, cookie, msg, NULL);
773			msg = NULL;
774		} else {
775			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
776			    UNI_CALLSTATE_U0);
777		}
778		break;
779	    }
780
781	  case SIGO_ALERTING_request:
782	    {
783		struct uniapi_alerting_request *arg =
784		    uni_msg_rptr(msg, struct uniapi_alerting_request *);
785
786		COMMON_DELAY(SIGO_ALERTING_request, cookie);
787		if ((c = uni_find_call(uni, &arg->alerting.hdr.cref)) != NULL) {
788			uni_enq_call(c, SIGC_ALERTING_request, cookie, msg, NULL);
789			msg = NULL;
790		} else {
791			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
792			    UNI_CALLSTATE_U0);
793		}
794		break;
795	    }
796
797	  case SIGO_SETUP_response:
798	    {
799		struct uniapi_setup_response *arg =
800		    uni_msg_rptr(msg, struct uniapi_setup_response *);
801
802		COMMON_DELAY(SIGO_SETUP_response, cookie);
803		if ((c = uni_find_call(uni, &arg->connect.hdr.cref)) != NULL) {
804			uni_enq_call(c, SIGC_SETUP_response, cookie, msg, NULL);
805			msg = NULL;
806		} else {
807			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
808			    UNI_CALLSTATE_U0);
809		}
810		break;
811	    }
812
813	  case SIGO_SETUP_COMPLETE_request:
814	    {
815		struct uniapi_setup_complete_request *arg =
816		    uni_msg_rptr(msg, struct uniapi_setup_complete_request *);
817
818		COMMON_DELAY(SIGO_SETUP_COMPLETE_request, cookie);
819		if ((c = uni_find_call(uni, &arg->connect_ack.hdr.cref)) != NULL) {
820			uni_enq_call(c, SIGC_SETUP_COMPLETE_request,
821			    cookie, msg, NULL);
822			msg = NULL;
823		} else {
824			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
825			    UNI_CALLSTATE_U0);
826		}
827		break;
828	    }
829
830	  case SIGO_RELEASE_request:
831	    {
832		struct uniapi_release_request *arg =
833		    uni_msg_rptr(msg, struct uniapi_release_request *);
834
835		COMMON_DELAY(SIGO_RELEASE_request, cookie);
836		if ((c = uni_find_call(uni, &arg->release.hdr.cref)) != NULL) {
837			uni_enq_call(c, SIGC_RELEASE_request, cookie, msg, NULL);
838			msg = NULL;
839		} else {
840			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
841			    UNI_CALLSTATE_U0);
842		}
843		break;
844	    }
845
846	  case SIGO_RELEASE_response:
847	    {
848		struct uniapi_release_response *arg =
849		    uni_msg_rptr(msg, struct uniapi_release_response *);
850
851		COMMON_DELAY(SIGO_RELEASE_response, cookie);
852		if ((c = uni_find_call(uni, &arg->release_compl.hdr.cref)) != NULL) {
853			uni_enq_call(c, SIGC_RELEASE_response, cookie, msg, NULL);
854			msg = NULL;
855		} else {
856			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
857			    UNI_CALLSTATE_U0);
858		}
859		break;
860	    }
861
862	  case SIGO_NOTIFY_request:
863	    {
864		struct uniapi_notify_request *arg =
865		    uni_msg_rptr(msg, struct uniapi_notify_request *);
866
867		COMMON_DELAY(SIGO_NOTIFY_request, cookie);
868		if ((c = uni_find_call(uni, &arg->notify.hdr.cref)) != NULL) {
869			uni_enq_call(c, SIGC_NOTIFY_request, cookie, msg, NULL);
870			msg = NULL;
871		} else {
872			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
873			    UNI_CALLSTATE_U0);
874		}
875		break;
876	    }
877
878	  case SIGO_STATUS_ENQUIRY_request:
879	    {
880		struct uniapi_status_enquiry_request *arg =
881		    uni_msg_rptr(msg, struct uniapi_status_enquiry_request *);
882
883		COMMON_DELAY(SIGO_STATUS_ENQUIRY_request, cookie);
884		if ((c = uni_find_call(uni, &arg->cref)) != NULL) {
885			uni_enq_call(c, SIGC_STATUS_ENQUIRY_request, cookie, msg, NULL);
886			msg = NULL;
887		} else {
888			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
889			    UNI_CALLSTATE_U0);
890		}
891		break;
892	    }
893
894	  case SIGO_ADD_PARTY_request:
895	    {
896		struct uniapi_add_party_request *arg =
897		    uni_msg_rptr(msg, struct uniapi_add_party_request *);
898
899		COMMON_DELAY(SIGO_ADD_PARTY_request, cookie);
900		if ((c = uni_find_call(uni, &arg->add.hdr.cref)) != NULL) {
901			if (c->type != CALL_ROOT) {
902				uniapi_call_error(c, UNIAPI_ERROR_BAD_CTYPE,
903				    cookie);
904				break;
905			}
906			uni_enq_call(c, SIGC_ADD_PARTY_request, cookie, msg, NULL);
907			msg = NULL;
908		} else {
909			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
910			    UNI_CALLSTATE_U0);
911		}
912		break;
913	    }
914
915	  case SIGO_PARTY_ALERTING_request:
916	    {
917		struct uniapi_party_alerting_request *arg =
918		    uni_msg_rptr(msg, struct uniapi_party_alerting_request *);
919
920		COMMON_DELAY(SIGO_PARTY_ALERTING_request, cookie);
921		if ((c = uni_find_call(uni, &arg->alert.hdr.cref)) != NULL) {
922			if (c->type != CALL_LEAF) {
923				uniapi_call_error(c, UNIAPI_ERROR_BAD_CTYPE,
924				    cookie);
925				break;
926			}
927			uni_enq_call(c, SIGC_PARTY_ALERTING_request, cookie, msg, NULL);
928			msg = NULL;
929		} else {
930			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
931			    UNI_CALLSTATE_U0);
932		}
933		break;
934	    }
935
936	  case SIGO_ADD_PARTY_ACK_request:
937	    {
938		struct uniapi_add_party_ack_request *arg =
939		    uni_msg_rptr(msg, struct uniapi_add_party_ack_request *);
940
941		COMMON_DELAY(SIGO_ADD_PARTY_ACK_request, cookie);
942		if ((c = uni_find_call(uni, &arg->ack.hdr.cref)) != NULL) {
943			if (c->type != CALL_LEAF) {
944				uniapi_call_error(c, UNIAPI_ERROR_BAD_CTYPE,
945				    cookie);
946				break;
947			}
948			uni_enq_call(c, SIGC_ADD_PARTY_ACK_request, cookie, msg, NULL);
949			msg = NULL;
950		} else {
951			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
952			    UNI_CALLSTATE_U0);
953		}
954		break;
955	    }
956
957	  case SIGO_ADD_PARTY_REJ_request:
958	    {
959		struct uniapi_add_party_rej_request *arg =
960		    uni_msg_rptr(msg, struct uniapi_add_party_rej_request *);
961
962		COMMON_DELAY(SIGO_ADD_PARTY_REJ_request, cookie);
963		if ((c = uni_find_call(uni, &arg->rej.hdr.cref)) != NULL) {
964			if (c->type != CALL_LEAF) {
965				uniapi_call_error(c, UNIAPI_ERROR_BAD_CTYPE,
966				    cookie);
967				break;
968			}
969			uni_enq_call(c, SIGC_ADD_PARTY_REJ_request, cookie, msg, NULL);
970			msg = NULL;
971		} else {
972			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
973			    UNI_CALLSTATE_U0);
974		}
975		break;
976	    }
977
978	  case SIGO_DROP_PARTY_request:
979	    {
980		struct uniapi_drop_party_request *arg =
981		    uni_msg_rptr(msg, struct uniapi_drop_party_request *);
982
983		COMMON_DELAY(SIGO_DROP_PARTY_request, cookie);
984		if ((c = uni_find_call(uni, &arg->drop.hdr.cref)) != NULL) {
985			if (c->type != CALL_ROOT && c->type != CALL_LEAF) {
986				uniapi_call_error(c, UNIAPI_ERROR_BAD_CTYPE,
987				    cookie);
988				break;
989			}
990			uni_enq_call(c, SIGC_DROP_PARTY_request, cookie, msg, NULL);
991			msg = NULL;
992		} else {
993			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
994			    UNI_CALLSTATE_U0);
995		}
996		break;
997	    }
998
999	  case SIGO_DROP_PARTY_ACK_request:
1000	    {
1001		struct uniapi_drop_party_ack_request *arg =
1002		    uni_msg_rptr(msg, struct uniapi_drop_party_ack_request *);
1003
1004		COMMON_DELAY(SIGO_DROP_PARTY_ACK_request, cookie);
1005		if ((c = uni_find_call(uni, &arg->ack.hdr.cref)) != NULL) {
1006			if (c->type != CALL_ROOT && c->type != CALL_LEAF) {
1007				uniapi_call_error(c, UNIAPI_ERROR_BAD_CTYPE,
1008				    cookie);
1009				break;
1010			}
1011			uni_enq_call(c, SIGC_DROP_PARTY_ACK_request, cookie, msg, NULL);
1012			msg = NULL;
1013		} else {
1014			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
1015			    UNI_CALLSTATE_U0);
1016		}
1017		break;
1018	    }
1019
1020	  case SIGO_ABORT_CALL_request:
1021	    {
1022		struct uniapi_abort_call_request *arg =
1023		    uni_msg_rptr(msg, struct uniapi_abort_call_request *);
1024
1025		if ((c = uni_find_call(uni, &arg->cref)) != NULL) {
1026			uni_enq_call(c, SIGC_ABORT_CALL_request, cookie, NULL, NULL);
1027		} else {
1028			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
1029			    UNI_CALLSTATE_U0);
1030		}
1031		break;
1032	    }
1033
1034	  /*
1035	   * Call-Control
1036	   */
1037	  case SIGO_CALL_DESTROYED:
1038		uni->funcs->uni_output(uni, uni->arg,
1039		    UNIAPI_CALL_DESTROYED, 0, msg);
1040		msg = NULL;
1041		break;
1042
1043	  /*
1044	   * ResetRespond
1045	   */
1046	  case SIGO_RESET_indication:
1047		uni->funcs->uni_output(uni, uni->arg,
1048		    UNIAPI_RESET_indication, 0, msg);
1049		msg = NULL;
1050		break;
1051
1052	  /*
1053	   * Timeouts
1054	   */
1055	  case SIGO_T309:
1056		coord_t309(uni);
1057		break;
1058
1059	}
1060	if (msg != NULL)
1061		uni_msg_destroy(msg);
1062}
1063
1064/*
1065 * Send a signal to all call instances
1066 */
1067static void
1068sig_all_calls(struct uni *uni, u_int sig)
1069{
1070	struct call *call;
1071
1072	TAILQ_FOREACH(call, &uni->calls, link)
1073		uni_enq_call(call, sig, 0, NULL, NULL);
1074}
1075
1076/*
1077 * Set a new coordinator state - this moves all delayed coordinator
1078 * signals from the delayed queue to the signal queue.
1079 */
1080static int
1081cufilt(struct sig *s, void *arg __unused)
1082{
1083	return (s->type == SIG_COORD);
1084}
1085
1086static void
1087set_custat(struct uni *uni, enum cu_stat nstate)
1088{
1089	if (uni->custat != nstate) {
1090		uni->custat = nstate;
1091		uni_undel(uni, cufilt, NULL);
1092	}
1093}
1094
1095/*
1096 * T309 timeout function
1097 */
1098static void
1099t309_func(struct uni *uni)
1100{
1101	uni_enq_coord(uni, SIGO_T309, 0, NULL);
1102}
1103
1104/*
1105 * Respond with a status message
1106 */
1107void
1108uni_respond_status(struct uni *uni, struct uni_cref *cref,
1109    enum uni_callstate cs, enum uni_cause c1)
1110{
1111	struct uni_all *resp;
1112
1113	if ((resp = UNI_ALLOC()) == NULL)
1114		return;
1115
1116	MK_MSG_RESP(resp, UNI_STATUS, cref);
1117	MK_IE_CALLSTATE(resp->u.status.callstate, cs);
1118	MK_IE_CAUSE(resp->u.status.cause, UNI_CAUSE_LOC_USER, c1);
1119
1120	(void)uni_send_output(resp, uni);
1121
1122	UNI_FREE(resp);
1123}
1124
1125/*
1126 * Respond with a status message
1127 */
1128void
1129uni_respond_status_mtype(struct uni *uni, struct uni_cref *cref,
1130    enum uni_callstate cs, enum uni_cause c1, u_int mtype)
1131{
1132	struct uni_all *resp;
1133
1134	if((resp = UNI_ALLOC()) == NULL)
1135		return;
1136
1137	MK_MSG_RESP(resp, UNI_STATUS, cref);
1138	MK_IE_CALLSTATE(resp->u.status.callstate, cs);
1139	MK_IE_CAUSE(resp->u.status.cause, UNI_CAUSE_LOC_USER, c1);
1140	ADD_CAUSE_MTYPE(resp->u.status.cause, mtype);
1141
1142	(void)uni_send_output(resp, uni);
1143
1144	UNI_FREE(resp);
1145}
1146
1147/*
1148 * Send a message. If we are in CUSTAT1, delay the message if we
1149 * are in CUSTAT3 send it, else drop it.
1150 */
1151int
1152uni_send_output(struct uni_all *u, struct uni *uni)
1153{
1154	struct uni_msg *m;
1155	int err;
1156
1157	if (uni->custat == CU_STAT0 || uni->custat == CU_STAT2)
1158		return (0);
1159
1160	m = uni_msg_alloc(1024);
1161	if ((err = uni_encode(m, u, &uni->cx)) != 0) {
1162		VERBOSE0(uni, UNI_FAC_ERR, "uni_encode failed: %08x", err);
1163		uni_msg_destroy(m);
1164		return (-1);
1165	}
1166	if (uni->custat == CU_STAT1)
1167		uni_delenq_coord(uni, SIGO_DATA, 0, m);
1168	else
1169		uni->funcs->saal_output(uni, uni->arg, SAAL_DATA_request, m);
1170	return (0);
1171}
1172