]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/contrib/ngatm/netnatm/sig/sig_coord.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / contrib / ngatm / netnatm / sig / sig_coord.c
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
44 static 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,
52 static const char *const coord_sigs[] = {
53         DEF_COORD_SIGS
54 };
55 #undef DEF_PRIV_SIG
56
57 static void sig_all_calls(struct uni *, u_int sig);
58 static void set_custat(struct uni *, enum cu_stat);
59
60 static void input_dummy(struct uni *uni, struct uni_msg *m, struct uni_all *u);
61 static void input_global(struct uni *uni, struct uni_msg *m, struct uni_all *u);
62 static void input_unknown(struct uni *uni, struct uni_msg *m, struct uni_all *u);
63 static void input_cobi(struct call *c, struct uni_msg *m, struct uni_all *u);
64 static void input_call(struct call *c, struct uni_msg *m, struct uni_all *u);
65
66 TIMER_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  */
79 static void
80 coord_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  */
104 static void
105 coord_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  */
143 static void
144 coord_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  */
172 static void
173 coord_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  */
202 static void
203 coord_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  */
254 static void
255 coord_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  */
283 static void
284 coord_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  */
315 static void
316 coord_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  */
358 static void
359 input_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  */
419 static void
420 input_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
532 static void
533 input_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
540 static void
541 input_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
548 static void
549 input_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  */
652 void
653 uni_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  */
1067 static void
1068 sig_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  */
1080 static int
1081 cufilt(struct sig *s, void *arg __unused)
1082 {
1083         return (s->type == SIG_COORD);
1084 }
1085
1086 static void
1087 set_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  */
1098 static void
1099 t309_func(struct uni *uni)
1100 {
1101         uni_enq_coord(uni, SIGO_T309, 0, NULL);
1102 }
1103
1104 /*
1105  * Respond with a status message
1106  */
1107 void
1108 uni_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  */
1128 void
1129 uni_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  */
1151 int
1152 uni_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 }