The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/ngatm/netnatm/sig/sig_call.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 }

Cache object: f85b48d2b94f963e6d5c5e792e47693f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.