]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/contrib/ngatm/netnatm/sig/sig_call.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / contrib / ngatm / netnatm / sig / sig_call.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_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
50 static enum call_state state_compat(struct call *, enum uni_callstate);
51 static 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,
55 static const char *const call_sigs[] = {
56         DEF_CALL_SIGS
57 };
58 #undef DEF_PRIV_SIG
59
60 TIMER_FUNC_CALL(t308, t308_func)
61 TIMER_FUNC_CALL(t303, t303_func)
62 TIMER_FUNC_CALL(t301, t301_func)
63 TIMER_FUNC_CALL(t310, t310_func)
64 TIMER_FUNC_CALL(t313, t313_func)
65 TIMER_FUNC_CALL(t322, t322_func)
66
67 const 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
91 static void unx_send_add_party_rej(struct call *c, struct uni_all *u);
92
93 static __inline void
94 set_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
111 static enum uni_callstate
112 map_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  */
122 struct call *
123 uni_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 }
132 struct call *
133 uni_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  */
146 struct call *
147 uni_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
187 struct call *
188 uni_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  */
212 void
213 uni_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
253 static void
254 allocate_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
277 static void
278 reset_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  */
303 static void
304 clear_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  */
359 static void
360 un0_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  */
468 static void
469 un0_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  */
546 static void
547 u1n6_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  */
639 static void
640 u1n6_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  */
690 static void
691 u3n9_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  */
706 static void
707 u4n7_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  */
730 static void
731 unx_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  */
831 static void
832 u6n1_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  */
868 static void
869 unx_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  */
917 static void
918 unx_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  */
982 static void
983 n8_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  */
1027 static void
1028 unx_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  */
1159 static void
1160 u8_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  */
1175 static void
1176 u8_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  */
1251 static void
1252 n10_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  */
1292 static void
1293 unx_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  */
1333 void
1334 uni_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 }
1368 static void
1369 unx_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  */
1387 static void
1388 unx_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  */
1440 static void
1441 u11n12_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  */
1475 static void
1476 unx_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  */
1547 static void
1548 unx_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  */
1578 static void
1579 unx_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  */
1626 static void
1627 respond_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  */
1648 static void
1649 u11n12_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  */
1701 static void
1702 un11un12_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
1791 static int
1792 status_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  */
1805 static void
1806 unx_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  */
1945 static void
1946 unx_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  */
1995 static void
1996 unx_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  */
2027 static void
2028 unx_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  */
2090 static void
2091 un10_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  */
2111 static void
2112 unx_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  */
2142 static void
2143 un10_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  */
2173 static void
2174 call_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  */
2199 static void
2200 un10_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  */
2224 static void
2225 unx_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  */
2236 static void
2237 un10_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  */
2257 static void
2258 unx_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
2276 static void
2277 make_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  */
2301 static void
2302 ux_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  */
2324 static void
2325 nx_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  */
2353 static void
2354 ux_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  */
2376 static void
2377 nx_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  */
2405 static void
2406 ux_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  */
2428 static void
2429 nx_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  */
2460 static void
2461 unx_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  */
2506 static void
2507 un10_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  */
2541 static void
2542 unx_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  */
2576 static void
2577 unx_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  */
2610 static void
2611 unx_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  */
2639 static void
2640 unx_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  */
2673 static void
2674 unx_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  */
2796 static void
2797 un10n8_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  */
2874 static void
2875 default_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  */
2896 static void
2897 unx_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  */
2978 static void
2979 handle_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  */
3005 static void
3006 unx_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  */
3028 static void
3029 unx_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  */
3101 static void
3102 unx_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  */
3184 static void
3185 unx_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  */
3252 void
3253 uni_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  */
3309 static void
3310 unx_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
3333 void
3334 uni_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  */
4224 static void
4225 t308_func(struct call *c)
4226 {
4227         uni_enq_call(c, SIGC_T308, 0, NULL, NULL);
4228 }
4229 static void
4230 t303_func(struct call *c)
4231 {
4232         uni_enq_call(c, SIGC_T303, 0, NULL, NULL);
4233 }
4234 static void
4235 t301_func(struct call *c)
4236 {
4237         uni_enq_call(c, SIGC_T301, 0, NULL, NULL);
4238 }
4239 static void
4240 t310_func(struct call *c)
4241 {
4242         uni_enq_call(c, SIGC_T310, 0, NULL, NULL);
4243 }
4244 static void
4245 t313_func(struct call *c)
4246 {
4247         uni_enq_call(c, SIGC_T313, 0, NULL, NULL);
4248 }
4249
4250 static void
4251 t322_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  */
4270 static enum call_state
4271 state_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 }