]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/contrib/ngatm/netnatm/sig/sig_party.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / contrib / ngatm / netnatm / sig / sig_party.c
1 /*
2  * Copyright (c) 1996-2003
3  *      Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4  *      All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * Author: Hartmut Brandt <harti@freebsd.org>
28  *
29  * $Begemot: libunimsg/netnatm/sig/sig_party.c,v 1.18 2004/08/05 07:11:01 brandt Exp $
30  *
31  * Party instance handling
32  */
33
34 #include <netnatm/unimsg.h>
35 #include <netnatm/saal/sscfudef.h>
36 #include <netnatm/msg/unistruct.h>
37 #include <netnatm/msg/unimsglib.h>
38 #include <netnatm/sig/uni.h>
39
40 #include <netnatm/sig/unipriv.h>
41 #include <netnatm/sig/unimkmsg.h>
42 #include <netnatm/sig/unimsgcpy.h>
43
44 static void drop_partyE(struct party *p);
45 static int epstate_compat(struct party *, enum uni_epstate);
46
47 #define DEF_PRIV_SIG(NAME, FROM)        [SIG##NAME] =   "SIG"#NAME,
48 static const char *const party_sigs[] = {
49         DEF_PARTY_SIGS
50 };
51 #undef DEF_PRIV_SIG
52
53 TIMER_FUNC_PARTY(t397, t397_func)
54 TIMER_FUNC_PARTY(t398, t398_func)
55 TIMER_FUNC_PARTY(t399, t399_func)
56
57 static __inline void
58 set_party_state(struct party *p, enum uni_epstate state)
59 {
60         if (p->state != state) {
61                 VERBOSE(p->call->uni, UNI_FAC_CALL, 1,
62                     "party %u/%u %u/%u PU%u -> PU%u",
63                     p->call->cref, p->call->mine,
64                     p->epref, p->flags & PARTY_MINE, p->state, state);
65                 p->state = state;
66         }
67 }
68
69 /*
70  * Create a party with a given endpoint reference.
71  * No check is done, that a party with this epref does not alreay exist.
72  */
73 struct party *
74 uni_create_partyx(struct call *c, u_int epref, u_int mine, uint32_t cookie)
75 {
76         struct party *p;
77         struct uni_msg *api;
78         struct uniapi_party_created *ind;
79
80         mine = (mine ? PARTY_MINE : 0);
81
82         if ((p = PARTY_ALLOC()) == NULL)
83                 return (NULL);
84
85         if ((ind = ALLOC_API(struct uniapi_party_created, api)) == NULL) {
86                 PARTY_FREE(p);
87                 return (NULL);
88         }
89
90         ind->cref.cref = c->cref;
91         ind->cref.flag = c->mine;
92         MK_IE_EPREF(ind->epref, epref, mine);
93         ind->epref.h.act = UNI_IEACT_DEFAULT;
94
95         p->call = c;
96         p->epref = epref;
97         p->flags = mine;
98         p->state = UNI_EPSTATE_NULL;;
99
100         TIMER_INIT_PARTY(p, t397);
101         TIMER_INIT_PARTY(p, t398);
102         TIMER_INIT_PARTY(p, t399);
103
104         TAILQ_INSERT_HEAD(&c->parties, p, link);
105
106         c->uni->funcs->uni_output(c->uni, c->uni->arg,
107             UNIAPI_PARTY_CREATED, cookie, api);
108
109         VERBOSE(c->uni, UNI_FAC_CALL, 1, "created party %u/%s %u/%s",
110             p->call->cref, p->call->mine ? "mine" : "his",
111             p->epref, (p->flags & PARTY_MINE) ? "mine" : "his");
112
113         return (p);
114         
115 }
116
117 struct party *
118 uni_create_party(struct call *c, struct uni_ie_epref *epref)
119 {
120         return (uni_create_partyx(c, epref->epref, epref->flag, 0));
121 }
122
123 struct party *
124 uni_find_party(struct call *c, struct uni_ie_epref *epref)
125 {
126         struct party *p;
127
128         TAILQ_FOREACH(p, &c->parties, link)
129                 if (p->epref == epref->epref &&
130                     (!(p->flags & PARTY_MINE) == !epref->flag))
131                         return (p);
132         return (NULL);
133 }
134 struct party *
135 uni_find_partyx(struct call *c, u_int epref, u_int mine)
136 {
137         struct party *p;
138
139         TAILQ_FOREACH(p, &c->parties, link)
140                 if (p->epref == epref && (!(p->flags & PARTY_MINE) == !mine))
141                         return (p);
142         return (NULL);
143 }
144
145 /*
146  * Destroy a party.
147  * This function is assumed to remove the party from the parent's call
148  * party list.
149  */
150 void
151 uni_destroy_party(struct party *p, int really)
152 {
153         struct uni_msg *api;
154         struct uniapi_party_destroyed *ind;
155
156         TIMER_DESTROY_PARTY(p, t397);
157         TIMER_DESTROY_PARTY(p, t398);
158         TIMER_DESTROY_PARTY(p, t399);
159
160         TAILQ_REMOVE(&p->call->parties, p, link);
161
162         uni_delsig(p->call->uni, SIG_PARTY, p->call, p);
163
164         if (!really) {
165                 ind = ALLOC_API(struct uniapi_party_destroyed, api);
166                 if (ind != NULL) {
167                         ind->cref.cref = p->call->cref;
168                         ind->cref.flag = p->call->mine;
169                         ind->epref.epref = p->epref;
170                         ind->epref.flag = p->flags & PARTY_MINE;
171                         ind->epref.h.act = UNI_IEACT_DEFAULT;
172                         IE_SETPRESENT(ind->epref);
173
174                         uni_enq_call(p->call, SIGC_PARTY_DESTROYED, 0, api, NULL);
175                 }
176
177                 uni_enq_party(p, SIGP_PARTY_DELETE, 0, NULL, NULL);
178                 return;
179         }
180         PARTY_FREE(p);
181 }
182
183 /*
184  * Count number of parties in active states.
185  * If the argument is 0 only ACTIVE parties are counter
186  * If the argument is 1 only parties in establishing states are counted
187  * If the argument is 2 both are counted.
188  */
189 u_int
190 uni_party_act_count(struct call *c, int kind)
191 {
192         struct party *p;
193         u_int cnt;
194
195         cnt = 0;
196         TAILQ_FOREACH(p, &c->parties, link) {
197                 switch (p->state) {
198
199                   case UNI_EPSTATE_ACTIVE:
200                         if (kind == 0 || kind == 2)
201                                 cnt++;
202                         break;
203
204                   case UNI_EPSTATE_ALERT_RCVD:
205                   case UNI_EPSTATE_ADD_INIT:
206                   case UNI_EPSTATE_ALERT_DLVD:
207                   case UNI_EPSTATE_ADD_RCVD:
208                         if (kind == 1 || kind == 2)
209                                 cnt++;
210                         break;
211
212                   default:
213                         break;
214                 }
215         }
216         return (cnt);
217 }
218
219 static void
220 stop_all_party_timers(struct party *p)
221 {
222         TIMER_STOP_PARTY(p, t397);
223         TIMER_STOP_PARTY(p, t398);
224         TIMER_STOP_PARTY(p, t399);
225 }
226 /************************************************************/
227
228 /*
229  * Add-party.request
230  *
231  * Q.2971:Party-control-U 3 (PU0)
232  * Q.2971:Party-control-N 3 (PN0)
233  */
234 static void
235 pun0_add_party_request(struct party *p, struct uni_msg *api, uint32_t cookie)
236 {
237         struct uni_all *add;
238         struct uniapi_add_party_request *req =
239             uni_msg_rptr(api, struct uniapi_add_party_request *);
240
241         if ((add = UNI_ALLOC()) == NULL) {
242                 uni_msg_destroy(api);
243                 uniapi_party_error(p, UNIAPI_ERROR_NOMEM, cookie);
244                 return;
245         }
246
247         add->u.add_party = req->add;
248         MK_MSG_ORIG(add, UNI_ADD_PARTY, p->call->cref, !p->call->mine);
249         uni_send_output(add, p->call->uni);
250         UNI_FREE(add);
251
252         TIMER_START_PARTY(p, t399, p->call->uni->timer399);
253
254         set_party_state(p, UNI_EPSTATE_ADD_INIT);
255
256         uni_msg_destroy(api);
257         uniapi_party_error(p, UNIAPI_OK, cookie);
258 }
259
260 /*
261  * Add-party-ack.request
262  *
263  * Q.2971:Party-Control-U 6 PU2
264  * Q.2971:Party-Control-U 7 PU3
265  * Q.2971:Party-Control-N 6 PN2
266  * Q.2971:Party-Control-N 7 PN3
267  */
268 static void
269 punx_add_party_ack_request(struct party *p, struct uni_msg *m, uint32_t cookie)
270 {
271         struct uni_all *ack;
272         struct uniapi_add_party_ack_request *req =
273             uni_msg_rptr(m, struct uniapi_add_party_ack_request *);
274
275         if ((ack = UNI_ALLOC()) == NULL) {
276                 uniapi_party_error(p, UNIAPI_ERROR_NOMEM, cookie);
277                 uni_msg_destroy(m);
278                 return;
279         }
280         ack->u.add_party_ack = req->ack;
281         MK_MSG_ORIG(ack, UNI_ADD_PARTY_ACK, p->call->cref, !p->call->mine);
282         uni_send_output(ack, p->call->uni);
283         UNI_FREE(ack);
284
285         set_party_state(p, UNI_EPSTATE_ACTIVE);
286
287         uni_msg_destroy(m);
288         uniapi_party_error(p, UNIAPI_OK, cookie);
289 }
290
291 /*
292  * Add-party-rej.request
293  *
294  * Q.2971:Party-Control-U 6 PU2
295  * Q.2971:Party-Control-N 6 PN2
296  */
297 static void
298 pun2_add_party_rej_request(struct party *p, struct uni_msg *m, uint32_t cookie)
299 {
300         struct uni_all *rej;
301         struct uniapi_add_party_rej_request *req =
302             uni_msg_rptr(m, struct uniapi_add_party_rej_request *);
303
304         if ((rej = UNI_ALLOC()) == NULL) {
305                 uniapi_party_error(p, UNIAPI_ERROR_NOMEM, cookie);
306                 uni_msg_destroy(m);
307                 return;
308         }
309
310         stop_all_party_timers(p);
311
312         rej->u.add_party_rej = req->rej;
313         MK_MSG_ORIG(rej, UNI_ADD_PARTY_REJ, p->call->cref, !p->call->mine);
314         uni_enq_call(p->call, SIGC_SEND_ADD_PARTY_REJ, cookie, NULL, rej);
315
316         uni_msg_destroy(m);
317         p->state = UNI_EPSTATE_NULL;
318         uniapi_party_error(p, UNIAPI_OK, cookie);
319
320         uni_destroy_party(p, 0);
321 }
322
323 /*
324  * ADD PARTY in PU0, PN0
325  *
326  * Q.2971:Party-Control-U 3/14 PU0
327  */
328 static void
329 pun0_add_party(struct party *p, struct uni_msg *m, struct uni_all *u)
330 {
331         struct uniapi_add_party_indication *ind;
332         struct uni_msg *api;
333
334         ind = ALLOC_API(struct uniapi_add_party_indication, api);
335         if (ind != NULL) {
336                 ind->add.hdr = u->u.hdr;
337                 copy_msg_add_party(&u->u.add_party, &ind->add);
338                 p->call->uni->funcs->uni_output(p->call->uni, p->call->uni->arg,
339                     UNIAPI_ADD_PARTY_indication, 0, api);
340         }
341         set_party_state(p, UNI_EPSTATE_ADD_RCVD);
342
343         uni_msg_destroy(m);
344         UNI_FREE(u);
345 }
346
347 /*
348  * PARTY-ALERTING.request
349  *
350  * Q.2971:Party-Control-U 6 (PU2)
351  * Q.2971:Party-Control-N 6 (PN2)
352  */
353 static void
354 pun2_party_alerting_request(struct party *p, struct uni_msg *api,
355     uint32_t cookie)
356 {
357         struct uni_all *alert;
358         struct uniapi_party_alerting_request *req =
359             uni_msg_rptr(api, struct uniapi_party_alerting_request *);
360
361         if ((alert = UNI_ALLOC()) == NULL) {
362                 uniapi_party_error(p, UNIAPI_ERROR_NOMEM, cookie);
363                 uni_msg_destroy(api);
364                 return;
365         }
366         alert->u.party_alerting = req->alert;
367         MK_MSG_ORIG(alert, UNI_PARTY_ALERTING,
368              p->call->cref, !p->call->mine);
369         uni_send_output(alert, p->call->uni);
370         UNI_FREE(alert);
371
372         set_party_state(p, UNI_EPSTATE_ALERT_DLVD);
373
374         uni_msg_destroy(api);
375         uniapi_party_error(p, UNIAPI_OK, cookie);
376 }
377
378 /*
379  * PARTY-ALERTING in state PU1/PN1
380  *
381  * Q.2971:Party-Control-U 14
382  * Q.2971:Party-Control-N 5
383  */
384 static void
385 pun1_party_alerting(struct party *p, struct uni_msg *m, struct uni_all *u)
386 {
387         struct uniapi_party_alerting_indication *ind;
388         struct uni_msg *api;
389
390         ind = ALLOC_API(struct uniapi_party_alerting_indication, api);
391         if (ind == NULL) {
392                 uni_msg_destroy(m);
393                 UNI_FREE(u);
394                 return;
395         }
396         TIMER_STOP_PARTY(p, t399);
397
398         ind->alert.hdr = u->u.hdr;
399         copy_msg_party_alerting(&u->u.party_alerting, &ind->alert);
400
401         p->call->uni->funcs->uni_output(p->call->uni, p->call->uni->arg,
402             UNIAPI_PARTY_ALERTING_indication, 0, api);
403
404         TIMER_START_PARTY(p, t397, p->call->uni->timer397);
405
406         uni_msg_destroy(m);
407         UNI_FREE(u);
408
409         set_party_state(p, UNI_EPSTATE_ALERT_RCVD);
410 }
411
412 /*
413  * ADD-PARTY-ACK
414  *
415  * Q.2971:Party-Control-U 4 (PU1)
416  * Q.2971:Party-Control-U 7 (PU4)
417  * Q.2971:Party-Control-N 4 (PN1)
418  * Q.2971:Party-Control-N 7 (PN4)
419  */
420 static void
421 pun1pun4_add_party_ack(struct party *p, struct uni_msg *m, struct uni_all *u)
422 {
423         struct uniapi_add_party_ack_indication *ind;
424         struct uni_msg *api;
425
426         ind = ALLOC_API(struct uniapi_add_party_ack_indication, api);
427         if (ind == NULL) {
428                 uni_msg_destroy(m);
429                 UNI_FREE(u);
430                 return;
431         }
432
433         if (p->state == UNI_EPSTATE_ADD_INIT)
434                 TIMER_STOP_PARTY(p, t399);
435         else
436                 TIMER_STOP_PARTY(p, t397);
437
438         ind->ack.hdr = u->u.hdr;
439         copy_msg_add_party_ack(&u->u.add_party_ack, &ind->ack);
440
441         p->call->uni->funcs->uni_output(p->call->uni, p->call->uni->arg,
442             UNIAPI_ADD_PARTY_ACK_indication, 0, api);
443
444         uni_msg_destroy(m);
445         UNI_FREE(u);
446
447         set_party_state(p, UNI_EPSTATE_ACTIVE);
448 }
449
450 /*
451  * ADD-PARTY-REJECT
452  *
453  * Q.2971:Party-Control-U 4 (PU1)
454  * Q.2971:Party-Control-N 4 (PN1)
455  */
456 static void
457 pun1_add_party_rej(struct party *p, struct uni_msg *m, struct uni_all *u)
458 {
459         struct uniapi_add_party_rej_indication *ind;
460         struct uni_msg *api;
461
462         ind = ALLOC_API(struct uniapi_add_party_rej_indication, api);
463         if (ind == NULL) {
464                 uni_msg_destroy(m);
465                 UNI_FREE(u);
466                 return;
467         }
468
469         TIMER_STOP_PARTY(p, t399);
470
471         ind->rej.hdr = u->u.hdr;
472         copy_msg_add_party_rej(&u->u.add_party_rej, &ind->rej);
473         uni_enq_call(p->call, SIGC_ADD_PARTY_REJ_indication, 0, api, NULL);
474
475         uni_destroy_party(p, 0);
476
477         uni_msg_destroy(m);
478         UNI_FREE(u);
479 }
480
481 /*
482  * ADD-PARTY-REJECT
483  *
484  * Q.2971:Party-Control-U 10 (PU5)
485  * Q.2971:Party-Control-N 10 (PN5)
486  */
487 static void
488 pun5_add_party_rej(struct party *p, struct uni_msg *m, struct uni_all *u)
489 {
490         struct uniapi_drop_party_ack_indication *ind;
491         struct uni_msg *api;
492
493         ind = ALLOC_API(struct uniapi_drop_party_ack_indication, api);
494         if (ind == NULL) {
495                 uni_msg_destroy(m);
496                 UNI_FREE(u);
497                 return;
498         }
499
500         ind->drop.hdr = u->u.hdr;
501         COPY_FROM_ADD_REJ(u, &ind->drop);
502         if (IE_ISGOOD(u->u.add_party_rej.crankback))
503                 ind->crankback = u->u.add_party_rej.crankback;
504         uni_enq_call(p->call, SIGC_DROP_PARTY_ACK_indication, 0, api, NULL);
505
506         TIMER_STOP_PARTY(p, t398);
507
508         uni_destroy_party(p, 0);
509
510         uni_msg_destroy(m);
511         UNI_FREE(u);
512 }
513
514 /*
515  * DROP-PARTY-ACKNOWLEDGE
516  *
517  * Q.2971:Party-Control-U 8
518  * Q.2971:Party-Control-N 8
519  *
520  * Message already verified in Call-Control!
521  */
522 static void
523 punx_drop_party_ack(struct party *p, struct uni_msg *m, struct uni_all *u)
524 {
525         struct uniapi_drop_party_ack_indication *ind;
526         struct uni_msg *api;
527
528         stop_all_party_timers(p);
529
530         ind = ALLOC_API(struct uniapi_drop_party_ack_indication, api);
531         if (ind != NULL) {
532                 ind->drop.hdr = u->u.hdr;
533                 COPY_FROM_DROP_ACK(u, &ind->drop);
534                 uni_enq_call(p->call, SIGC_DROP_PARTY_ACK_indication,
535                     0, api, NULL);
536         }
537
538         uni_destroy_party(p, 0);
539
540         uni_msg_destroy(m);
541         UNI_FREE(u);
542 }
543
544 /*
545  * DROP PARTY message in any state except PU5/PN5
546  *
547  * Q.2971:Party-Control-U 9
548  * Q.2971:Party-Control-N 9
549  */
550 static void
551 punx_drop_party(struct party *p, struct uni_msg *m, struct uni_all *u)
552 {
553         struct uniapi_drop_party_indication *ind;
554         struct uni_msg *api;
555
556         ind = ALLOC_API(struct uniapi_drop_party_indication, api);
557         if (ind == NULL) {
558                 uni_msg_destroy(m);
559                 UNI_FREE(u);
560                 return;
561         }
562
563         ind->drop.hdr = u->u.hdr;
564         copy_msg_drop_party(&u->u.drop_party, &ind->drop);
565
566         /* need the cause even if it is bad */
567         if (IE_ISERROR(u->u.drop_party.cause))
568                 ind->drop.cause = u->u.drop_party.cause;
569
570         ind->my_cause = p->call->uni->cause;
571
572         uni_enq_call(p->call, SIGC_DROP_PARTY_indication, 0, api, NULL);
573
574         TIMER_STOP_PARTY(p, t397);
575         TIMER_STOP_PARTY(p, t399);
576
577         uni_msg_destroy(m);
578         UNI_FREE(u);
579
580         set_party_state(p, UNI_EPSTATE_DROP_RCVD);
581 }
582
583 /*
584  * DROP PARTY message in state PU5/PN5
585  *
586  * Q.2971:Party-Control-U 10
587  * Q.2971:Party-Control-N 10
588  */
589 static void
590 pun5_drop_party(struct party *p, struct uni_msg *m, struct uni_all *u)
591 {
592         struct uniapi_drop_party_ack_indication *ind;
593         struct uni_msg *api;
594
595         ind = ALLOC_API(struct uniapi_drop_party_ack_indication, api);
596         if (ind == NULL) {
597                 uni_msg_destroy(m);
598                 UNI_FREE(u);
599                 return;
600         }
601
602         ind->drop.hdr = u->u.hdr;
603         copy_msg_drop_party(&u->u.drop_party, &ind->drop);
604
605         /* need the cause even if it is bad */
606         if (IE_ISERROR(u->u.drop_party.cause))
607                 ind->drop.cause = u->u.drop_party.cause;
608
609         uni_enq_call(p->call, SIGC_DROP_PARTY_ACK_indication, 0, api, NULL);
610
611         TIMER_STOP_PARTY(p, t398);
612
613         uni_msg_destroy(m);
614         UNI_FREE(u);
615
616         set_party_state(p, UNI_EPSTATE_DROP_RCVD);
617
618         uni_destroy_party(p, 0);
619 }
620
621 /************************************************************/
622
623 /*
624  * T399
625  *
626  * Q.2971:Party-Control-U 4 (PU1)
627  * Q.2971:Party-Control-N 4 (PN1)
628  */
629 static void
630 pun1_t399(struct party *p)
631 {
632         if (p->call->uni->proto == UNIPROTO_UNI40N) {
633                 MK_IE_CAUSE(p->call->uni->cause, UNI_CAUSE_LOC_USER,
634                     UNI_CAUSE_NO_RESPONSE);
635         } else {
636                 MK_IE_CAUSE(p->call->uni->cause, UNI_CAUSE_LOC_USER,
637                     UNI_CAUSE_RECOVER);
638                 ADD_CAUSE_TIMER(p->call->uni->cause, "399");
639         }
640
641         drop_partyE(p);
642 }
643
644 /*
645  * T398
646  *
647  * Q.2971:Party-Control-U 10 (PU5)
648  * Q.2971:Party-Control-N 10 (PN5)
649  */
650 static void
651 pun5_t398(struct party *p)
652 {
653         struct uniapi_drop_party_ack_indication *ind;
654         struct uni_all *drop;
655         struct uni_msg *api;
656
657         MK_IE_CAUSE(p->call->uni->cause,
658             UNI_CAUSE_LOC_USER, UNI_CAUSE_RECOVER);
659         ADD_CAUSE_TIMER(p->call->uni->cause, "398");
660         /*
661          * Send indication to API
662          */
663         ind = ALLOC_API(struct uniapi_drop_party_ack_indication, api);
664         if (ind != NULL) {
665                 ind->drop.hdr.cref.cref = p->call->cref;
666                 ind->drop.hdr.cref.flag = p->call->mine;
667                 ind->drop.hdr.act = UNI_MSGACT_DEFAULT;
668                 MK_IE_EPREF(ind->drop.epref, p->epref, p->flags & PARTY_MINE);
669                 ind->drop.cause = p->call->uni->cause;
670                 uni_enq_call(p->call, SIGC_DROP_PARTY_ACK_indication,
671                     0, api, NULL);
672         }
673
674         /*
675          * Send DROP PARTY ACK
676          */
677         if ((drop = UNI_ALLOC()) != NULL) {
678                 MK_MSG_ORIG(drop, UNI_DROP_PARTY_ACK,
679                     p->call->cref, !p->call->mine);
680                 MK_IE_EPREF(drop->u.drop_party_ack.epref,
681                     p->epref, !(p->flags & PARTY_MINE));
682                 drop->u.drop_party_ack.cause = p->call->uni->cause;
683                 uni_enq_call(p->call, SIGC_SEND_DROP_PARTY_ACK, 0, NULL, drop);
684         }
685
686         uni_destroy_party(p, 0);
687 }
688
689 /*
690  * T397
691  *
692  * Q.2971:Party-Control-U 7 (PU4)
693  * Q.2971:Party-Control-N 7 (PN4)
694  */
695 static void
696 pun4_t397(struct party *p)
697 {
698         MK_IE_CAUSE(p->call->uni->cause, UNI_CAUSE_LOC_USER,
699             UNI_CAUSE_RECOVER);
700         ADD_CAUSE_TIMER(p->call->uni->cause, "397");
701
702         drop_partyE(p);
703 }
704
705 /************************************************************/
706
707 /*
708  * Drop a party because of an error condition.
709  * This is label E on page Party-Control-U 8/14.
710  *
711  * It is assumed, that the caller has constructed the cause in
712  * p->call->uni->cause.
713  */
714 static void
715 drop_partyE(struct party *p)
716 {
717         struct uni_msg *api;
718         struct uniapi_drop_party_indication *ind;
719         struct uni_all *drop;
720
721         /*
722          * Send indication to API
723          */
724         if ((ind = ALLOC_API(struct uniapi_drop_party_indication, api)) != NULL) {
725                 ind->drop.hdr.cref.cref = p->call->cref;
726                 ind->drop.hdr.cref.flag = p->call->mine;
727                 ind->drop.hdr.act = UNI_MSGACT_DEFAULT;
728                 MK_IE_EPREF(ind->drop.epref, p->epref, p->flags & PARTY_MINE);
729                 ind->drop.cause = p->call->uni->cause;
730                 uni_enq_call(p->call, SIGC_DROP_PARTY_indication, 0, api, NULL);
731         }
732         TIMER_STOP_PARTY(p, t399);
733         TIMER_STOP_PARTY(p, t397);
734         TIMER_START_PARTY(p, t398, p->call->uni->timer398);
735
736         if ((drop = UNI_ALLOC()) != NULL) {
737                 drop->u.drop_party.cause = p->call->uni->cause;
738                 MK_MSG_ORIG(drop, UNI_DROP_PARTY, p->call->cref, !p->call->mine);
739                 MK_IE_EPREF(drop->u.drop_party.epref, p->epref,
740                     !(p->flags & PARTY_MINE));
741                 uni_enq_call(p->call, SIGC_SEND_DROP_PARTY, 0, NULL, drop);
742         }
743
744         set_party_state(p, UNI_EPSTATE_DROP_INIT);
745 }
746
747 /*
748  * Drop party request in Px1, Px3, Px4 or Px7
749  *
750  * Q.2971:Party-Control-U 8
751  * Q.2971:Party-Control-N 8
752  */
753 static void
754 punx_drop_party_request(struct party *p, struct uni_msg *api, uint32_t cookie)
755 {
756         struct uniapi_drop_party_request *req =
757             uni_msg_rptr(api, struct uniapi_drop_party_request *);
758         struct uni_all *drop;
759
760         if ((drop = UNI_ALLOC()) == NULL) {
761                 uniapi_party_error(p, UNIAPI_ERROR_NOMEM, cookie);
762                 uni_msg_destroy(api);
763                 return;
764         }
765
766         TIMER_STOP_PARTY(p, t399);
767         TIMER_STOP_PARTY(p, t397);
768         TIMER_START_PARTY(p, t398, p->call->uni->timer398);
769
770         drop->u.drop_party = req->drop;
771         MK_MSG_ORIG(drop, UNI_DROP_PARTY, p->call->cref, !p->call->mine);
772         uni_enq_call(p->call, SIGC_SEND_DROP_PARTY, cookie, NULL, drop);
773
774         set_party_state(p, UNI_EPSTATE_DROP_INIT);
775
776         uni_msg_destroy(api);
777         uniapi_party_error(p, UNIAPI_OK, cookie);
778 }
779
780 /*
781  * Drop-party-ack.request in Px6
782  *
783  * Q.2971:Party-Control-U 9
784  * Q.2971:Party-Control-N 9
785  */
786 static void
787 pun6_drop_party_ack_request(struct party *p, struct uni_msg *api, uint32_t cookie)
788 {
789         struct uniapi_drop_party_ack_request *req =
790             uni_msg_rptr(api, struct uniapi_drop_party_ack_request *);
791         struct uni_all *ack;
792
793         if ((ack = UNI_ALLOC()) == NULL) {
794                 uni_msg_destroy(api);
795                 uniapi_party_error(p, UNIAPI_ERROR_NOMEM, cookie);
796                 return;
797         }
798         ack->u.drop_party_ack = req->ack;
799         MK_MSG_ORIG(ack, UNI_DROP_PARTY_ACK, p->call->cref, !p->call->mine);
800         uni_enq_call(p->call, SIGC_SEND_DROP_PARTY_ACK, cookie, NULL, ack);
801
802         stop_all_party_timers(p);
803
804         uni_msg_destroy(api);
805         uniapi_party_error(p, UNIAPI_OK, cookie);
806
807         uni_destroy_party(p, 0);
808 }
809 /************************************************************/
810 /*
811  * Party status enquiry request from API or call-control
812  *
813  * Q.2971:Party-Control-U 12
814  * Q.2971:Party-Control-N 12
815  */
816 static void
817 punx_status_enquiry_request(struct party *p, uint32_t cookie)
818 {
819         struct uni_all *enq;
820
821         if((enq = UNI_ALLOC()) == NULL) {
822                 uniapi_party_error(p, UNIAPI_ERROR_NOMEM, cookie);
823                 return;
824         }
825         MK_IE_EPREF(enq->u.status_enq.epref, p->epref,
826             !(p->flags & PARTY_MINE));
827         MK_MSG_ORIG(enq, UNI_STATUS_ENQ, p->call->cref, !p->call->mine);
828         uni_enq_call(p->call, SIGC_SEND_STATUS_ENQ, cookie, NULL, enq);
829
830         uniapi_party_error(p, UNIAPI_OK, cookie);
831 }
832
833 /*
834  * STATUS in any state except PU5/PN5
835  *
836  * Q.2971:Party-Control-U 12
837  * Q.2971:Party-Control-N 12
838  */
839 static void
840 punx_status(struct party *p, struct uni_msg *m, struct uni_all *u)
841 {
842         struct uniapi_drop_party_ack_indication *ind;
843         struct uni_msg *api;
844
845         if (u->u.status.epstate.state == UNI_EPSTATE_NULL) {
846                 /* should not happend */
847                 ind = ALLOC_API(struct uniapi_drop_party_ack_indication, api);
848                 if (ind != NULL) {
849                         ind->drop.hdr = u->u.hdr;
850                         ind->drop.cause = u->u.status.cause;
851                         ind->drop.epref = u->u.status.epref;
852                         uni_enq_call(p->call, SIGC_DROP_PARTY_ACK_indication,
853                             0, api, NULL);
854                 }
855                 stop_all_party_timers(p);
856
857                 uni_destroy_party(p, 0);
858         } else {
859                 if (epstate_compat(p, u->u.status.epstate.state)) {
860                         if(u->u.status.cause.cause == UNI_CAUSE_MANDAT ||
861                            u->u.status.cause.cause == UNI_CAUSE_MTYPE_NIMPL ||
862                            u->u.status.cause.cause == UNI_CAUSE_IE_NIMPL ||
863                            u->u.status.cause.cause == UNI_CAUSE_IE_INV) {
864                                 MK_IE_CAUSE(p->call->uni->cause,
865                                     UNI_CAUSE_LOC_USER,
866                                     UNI_CAUSE_UNSPEC);
867                                 drop_partyE(p);
868                         }
869                 } else {
870                         MK_IE_CAUSE(p->call->uni->cause,
871                             UNI_CAUSE_LOC_USER,
872                             UNI_CAUSE_MSG_INCOMP);
873                         drop_partyE(p);
874                 }
875         }
876
877         uni_msg_destroy(m);
878         UNI_FREE(u);
879 }
880
881 /*
882  * STATUS in PU5/PN5
883  *
884  * Q.2971:Party-Control-U 10
885  * Q.2971:Party-Control-N 10
886  */
887 static void
888 pun5_status(struct party *p, struct uni_msg *m, struct uni_all *u)
889 {
890         struct uniapi_drop_party_ack_indication *ind;
891         struct uni_msg *api;
892
893         if (u->u.status.epstate.state == UNI_EPSTATE_NULL) {
894                 ind = ALLOC_API(struct uniapi_drop_party_ack_indication, api);
895                 if (ind != NULL) {
896                         ind->drop.hdr = u->u.hdr;
897                         ind->drop.cause = u->u.status.cause;
898                         ind->drop.epref = u->u.status.epref;
899                         uni_enq_call(p->call, SIGC_DROP_PARTY_ACK_indication,
900                             0, api, NULL);
901                 }
902                 TIMER_STOP_PARTY(p, t398);
903
904                 uni_destroy_party(p, 0);
905         }
906
907         uni_msg_destroy(m);
908         UNI_FREE(u);
909 }
910
911 /************************************************************/
912
913 void
914 uni_sig_party(struct party *p, enum party_sig sig, uint32_t cookie,
915     struct uni_msg *msg, struct uni_all *u)
916 {
917         if (sig >= SIGP_END) {
918                 VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
919                     "Signal %d outside of range to Party-Control", sig);
920                 if (msg)
921                         uni_msg_destroy(msg);
922                 if (u)
923                         UNI_FREE(u);
924                 return;
925         }
926         VERBOSE(p->call->uni, UNI_FAC_CALL, 1,
927             "Signal %s in state %u of party %u/%s (call %u/%s in state %s)"
928             "; cookie %u", party_sigs[sig], p->state, p->epref,
929             (p->flags & PARTY_MINE) ? "mine" : "his", p->call->cref,
930             p->call->mine ? "mine" : "his", callstates[p->call->cstate].name,
931             cookie);
932
933         switch (sig) {
934
935           case SIGP_PARTY_DELETE:
936                 PARTY_FREE(p);
937                 break;
938
939           /*
940            * Messages
941            */
942           case SIGP_SETUP:
943                 if (p->state == UNI_EPSTATE_NULL) {
944                         /* Q.2971:Call-Control-U 3/13 */
945                         /* Q.2971:Call-Control-N 3/13 */
946                         set_party_state(p, UNI_EPSTATE_ADD_RCVD);
947                         break;
948                 }
949                 VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
950                     "SETUP in ps=%u", p->state);
951                 break;
952
953           case SIGP_ALERTING:
954                 if (p->state == UNI_EPSTATE_ADD_INIT) {
955                         /* Q.2971:Call-Control-U 14 */
956                         /* Q.2971:Call-Control-N 5 */
957                         TIMER_START_PARTY(p, t397, p->call->uni->timer397);
958                         set_party_state(p, UNI_EPSTATE_ALERT_RCVD);
959                         break;
960                 }
961                 VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
962                     "ALERTING in ps=%u", p->state);
963                 break;
964
965           case SIGP_CONNECT:
966                 if (p->state == UNI_EPSTATE_ADD_INIT) {
967                         /* Q.2971:Call-Control-U 4/13 */
968                         TIMER_STOP_PARTY(p, t399);
969                         set_party_state(p, UNI_EPSTATE_ACTIVE);
970                         break;
971                 }
972                 if (p->state == UNI_EPSTATE_ALERT_RCVD) {
973                         /* Q.2971:Call-Control-U 7/13 */
974                         TIMER_STOP_PARTY(p, t397);
975                         set_party_state(p, UNI_EPSTATE_ACTIVE);
976                         break;
977                 }
978                 VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
979                     "CONNECT in ps=%u", p->state);
980                 break;
981
982           case SIGP_CONNECT_ACK:
983                 if (p->state == UNI_EPSTATE_ADD_RCVD ||
984                     p->state == UNI_EPSTATE_ALERT_DLVD) {
985                         /* Q.2971:Call-Control-U 6/13 */
986                         /* Q.2971:Call-Control-U 7/13 */
987                         p->flags &= ~PARTY_CONNECT;
988                         set_party_state(p, UNI_EPSTATE_ACTIVE);
989                         break;
990                 }
991                 VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
992                     "CONNECT in ps=%u", p->state);
993                 break;
994
995           case SIGP_RELEASE:
996                 if (p->state == UNI_EPSTATE_DROP_INIT) {
997                         /* Q.2971:Party-Control-U 10/14 */
998                         /* Q.2971:Party-Control-N 10/14 */
999                         TIMER_STOP_PARTY(p, t398);
1000                         uni_destroy_party(p, 0);
1001                         break;
1002                 }
1003                 /* Q.2971:Party-Control-U 11/14 */
1004                 /* Q.2971:Party-Control-N 11/14 */
1005                 TIMER_STOP_PARTY(p, t397);
1006                 TIMER_STOP_PARTY(p, t399);
1007                 uni_destroy_party(p, 0);
1008                 break;
1009
1010           case SIGP_RELEASE_COMPL:
1011                 /* Q.2971:Party-Control-U 11/14 */
1012                 /* Q.2971:Party-Control-N 11/14 */
1013                 stop_all_party_timers(p);
1014                 uni_destroy_party(p, 0);
1015                 break;
1016
1017           case SIGP_RELEASE_confirm:
1018                 /* not in the SDLs */
1019                 stop_all_party_timers(p);
1020                 uni_destroy_party(p, 0);
1021                 break;
1022
1023           case SIGP_RELEASE_request:
1024                 if (p->state == UNI_EPSTATE_DROP_INIT) {
1025                         /* Q.2971:Party-Control-U 10 */
1026                         /* Q.2971:Party-Control-N 10 */
1027                         uni_destroy_party(p, 0);
1028                         break;
1029                 }
1030                 /* Q.2971:Party-Control-U 11 */
1031                 /* Q.2971:Party-Control-N 11 */
1032                 TIMER_STOP_PARTY(p, t397);
1033                 TIMER_STOP_PARTY(p, t399);
1034                 uni_destroy_party(p, 0);
1035                 break;
1036
1037           case SIGP_RELEASE_response:
1038                 /* Q.2971:Party-Control-U 11 */
1039                 /* Q.2971:Party-Control-N 11 */
1040                 stop_all_party_timers(p);
1041                 uni_destroy_party(p, 0);
1042                 break;
1043
1044           case SIGP_ADD_PARTY:
1045                 if (p->state == UNI_EPSTATE_NULL) {
1046                         /* Q.2971:Party-Control-U 3 PU0 */
1047                         /* Q.2971:Party-Control-N 3 PN0 */
1048                         pun0_add_party(p, msg, u);
1049                         break;
1050                 }
1051                 if (p->state == UNI_EPSTATE_ADD_RCVD) {
1052                         /* Q.2971:Party-Control-U 6 PU2 */
1053                         /* Q.2971:Party-Control-N 6 PN2 */
1054                         uni_msg_destroy(msg);
1055                         UNI_FREE(u);
1056                         break;
1057                 }
1058                 uni_bad_message(p->call, u, UNI_CAUSE_MSG_INCOMP,
1059                     &u->u.add_party.epref, p->state);
1060                 uni_msg_destroy(msg);
1061                 UNI_FREE(u);
1062                 break;
1063
1064           case SIGP_PARTY_ALERTING:
1065                 if (p->state == UNI_EPSTATE_ADD_INIT) {
1066                         /* Q.2971:Party-Control-U 14 */
1067                         /* Q.2971:Party-Control-N 5 */
1068                         pun1_party_alerting(p, msg, u);
1069                         break;
1070                 }
1071                 uni_bad_message(p->call, u, UNI_CAUSE_MSG_INCOMP,
1072                     &u->u.party_alerting.epref, p->state);
1073                 uni_msg_destroy(msg);
1074                 UNI_FREE(u);
1075                 break;
1076
1077           case SIGP_ADD_PARTY_ACK:
1078                 if (p->state == UNI_EPSTATE_ADD_INIT ||
1079                     p->state == UNI_EPSTATE_ALERT_RCVD) {
1080                         /* Q.2971:Party-Control-U 4 (PU1) */
1081                         /* Q.2971:Party-Control-U 7 (PU4) */
1082                         /* Q.2971:Party-Control-N 4 (PN1) */
1083                         /* Q.2971:Party-Control-N 7 (PN4) */
1084                         pun1pun4_add_party_ack(p, msg, u);
1085                         break;
1086                 }
1087                 uni_bad_message(p->call, u, UNI_CAUSE_MSG_INCOMP,
1088                     &u->u.add_party_ack.epref, p->state);
1089                 uni_msg_destroy(msg);
1090                 UNI_FREE(u);
1091                 break;
1092
1093           case SIGP_ADD_PARTY_REJ:
1094                 if (p->state == UNI_EPSTATE_ADD_INIT) {
1095                         /* Q.2971:Party-Control-U 4 (PU1) */
1096                         /* Q.2971:Party-Control-N 4 (PN1) */
1097                         pun1_add_party_rej(p, msg, u);
1098                         break;
1099                 }
1100                 if (p->state == UNI_EPSTATE_DROP_INIT) {
1101                         /* Q.2971:Party-Control-U 10 (PU5) */
1102                         /* Q.2971:Party-Control-N 10 (PN5) */
1103                         pun5_add_party_rej(p, msg, u);
1104                         break;
1105                 }
1106                 uni_bad_message(p->call, u, UNI_CAUSE_MSG_INCOMP,
1107                     &u->u.add_party_rej.epref, p->state);
1108                 uni_msg_destroy(msg);
1109                 UNI_FREE(u);
1110                 break;
1111
1112           case SIGP_DROP_PARTY_ACK:
1113                 /* Q.2971:Party-Control-U 8 */
1114                 /* Q.2971:Party-Control-N 8 */
1115                 punx_drop_party_ack(p, msg, u);
1116                 break;
1117
1118           case SIGP_DROP_PARTY:
1119                 if (p->state == UNI_EPSTATE_DROP_INIT)
1120                         /* Q.2971:Party-Control-U 10 */
1121                         /* Q.2971:Party-Control-N 10 */
1122                         pun5_drop_party(p, msg, u);
1123                 else
1124                         /* Q.2971:Party-Control-U 9 */
1125                         /* Q.2971:Party-Control-N 9 */
1126                         punx_drop_party(p, msg, u);
1127                 break;
1128
1129           case SIGP_STATUS:
1130                 if (p->state == UNI_EPSTATE_DROP_INIT)
1131                         /* Q.2971:Party-Control-U 10 */
1132                         /* Q.2971:Party-Control-N 10 */
1133                         pun5_status(p, msg, u);
1134                 else
1135                         /* Q.2971:Party-Control-U 12 */
1136                         /* Q.2971:Party-Control-N 12 */
1137                         punx_status(p, msg, u);
1138                 break;
1139
1140           /*
1141            * User
1142            */
1143           case SIGP_SETUP_request:
1144                 if (p->state == UNI_EPSTATE_NULL) {
1145                         /* Q.2971:Party-Control-U 3 */
1146                         /* Q.2971:Party-Control-N 3 */
1147                         set_party_state(p, UNI_EPSTATE_ADD_INIT);
1148                         break;
1149                 }
1150                 VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
1151                     "SETUP.request in ps=%u", p->state);
1152                 uniapi_party_error(p, UNIAPI_ERROR_BAD_EPSTATE, cookie);
1153                 break;
1154
1155           case SIGP_SETUP_response:
1156                 if (p->state == UNI_EPSTATE_ADD_RCVD ||
1157                     p->state == UNI_EPSTATE_ALERT_DLVD) {
1158                         /* Q.2971:Party-Control-N 6 (PN2) */
1159                         /* Q.2971:Party-Control-N 7 (PN3) */
1160                         set_party_state(p, UNI_EPSTATE_ACTIVE);
1161                         break;
1162                 }
1163                 VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
1164                     "SETUP.response in ps=%u", p->state);
1165                 uniapi_party_error(p, UNIAPI_ERROR_BAD_EPSTATE, cookie);
1166                 break;
1167
1168           case SIGP_SETUP_COMPL_request:
1169                 if (p->state == UNI_EPSTATE_ADD_INIT) {
1170                         /* Q.2971:Party-Control-N 4 */
1171                         TIMER_STOP_PARTY(p, t399);
1172                         set_party_state(p, UNI_EPSTATE_ACTIVE);
1173                         break;
1174                 }
1175                 if (p->state == UNI_EPSTATE_ALERT_RCVD) {
1176                         /* Q.2971:Party-Control-N 7 */
1177                         TIMER_STOP_PARTY(p, t397);
1178                         set_party_state(p, UNI_EPSTATE_ACTIVE);
1179                         break;
1180                 }
1181                 VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
1182                     "SETUP_COMPL.request in ps=%u", p->state);
1183                 uniapi_party_error(p, UNIAPI_ERROR_BAD_EPSTATE, cookie);
1184                 break;
1185
1186           case SIGP_ADD_PARTY_request:
1187                 if (p->state == UNI_EPSTATE_NULL) {
1188                         /* Q.2971:Party-control-U 3 (PU0) */
1189                         /* Q.2971:Party-control-N 3 (PN0) */
1190                         pun0_add_party_request(p, msg, cookie);
1191                         break;
1192                 }
1193                 VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
1194                     "Add-party.request in ps=%u", p->state);
1195                 uniapi_party_error(p, UNIAPI_ERROR_BAD_EPSTATE, cookie);
1196                 uni_msg_destroy(msg);
1197                 break;
1198
1199           case SIGP_ALERTING_request:
1200                 /* Q.2971:Party-Control-U 6 (PU2) */
1201                 /* Q.2971:Party-Control-N 6 (PN2) */
1202                 set_party_state(p, UNI_EPSTATE_ALERT_DLVD);
1203                 break;
1204
1205           case SIGP_PARTY_ALERTING_request:
1206                 if (p->state == UNI_EPSTATE_ADD_RCVD) {
1207                         /* Q.2971:Party-Control-U 6 (PU2) */
1208                         /* Q.2971:Party-Control-N 6 (PN2) */
1209                         pun2_party_alerting_request(p, msg, cookie);
1210                         break;
1211                 }
1212                 VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
1213                     "Party-alerting.request in ps=%u", p->state);
1214                 uniapi_party_error(p, UNIAPI_ERROR_BAD_EPSTATE, cookie);
1215                 uni_msg_destroy(msg);
1216                 break;
1217
1218           case SIGP_ADD_PARTY_ACK_request:
1219                 if (p->state == UNI_EPSTATE_ADD_RCVD ||
1220                     p->state == UNI_EPSTATE_ALERT_DLVD) {
1221                         /* Q.2971:Party-Control-U 6 PU2 */
1222                         /* Q.2971:Party-Control-U 7 PU3 */
1223                         /* Q.2971:Party-Control-N 6 PN2 */
1224                         /* Q.2971:Party-Control-N 7 PN3 */
1225                         punx_add_party_ack_request(p, msg, cookie);
1226                         break;
1227                 }
1228                 VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
1229                     "Add-party-ack.request in ps=%u", p->state);
1230                 uniapi_party_error(p, UNIAPI_ERROR_BAD_EPSTATE, cookie);
1231                 uni_msg_destroy(msg);
1232                 break;
1233
1234           case SIGP_ADD_PARTY_REJ_request:
1235                 if (p->state == UNI_EPSTATE_ADD_RCVD) {
1236                         /* Q.2971:Party-Control-U 6 PU2 */
1237                         /* Q.2971:Party-Control-N 6 PN2 */
1238                         pun2_add_party_rej_request(p, msg, cookie);
1239                         break;
1240                 }
1241                 VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
1242                     "Add-party-rej.request in ps=%u", p->state);
1243                 uniapi_party_error(p, UNIAPI_ERROR_BAD_EPSTATE, cookie);
1244                 uni_msg_destroy(msg);
1245                 break;
1246
1247           case SIGP_DROP_PARTY_request:
1248                 if (p->state == UNI_EPSTATE_ADD_INIT ||
1249                     p->state == UNI_EPSTATE_ALERT_DLVD ||
1250                     p->state == UNI_EPSTATE_ALERT_RCVD ||
1251                     p->state == UNI_EPSTATE_ACTIVE) {
1252                         /* Q.2971:Party-Control-U 8 */
1253                         /* Q.2971:Party-Control-N 8 */
1254                         punx_drop_party_request(p, msg, cookie);
1255                         break;
1256                 }
1257                 VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
1258                     "Drop-party.request in ps=%u", p->state);
1259                 uniapi_party_error(p, UNIAPI_ERROR_BAD_EPSTATE, cookie);
1260                 uni_msg_destroy(msg);
1261                 break;
1262
1263           case SIGP_DROP_PARTY_ACK_request:
1264                 if (p->state == UNI_EPSTATE_DROP_RCVD) {
1265                         /* Q.2971:Party-Control-U 9 */
1266                         /* Q.2971:Party-Control-N 9 */
1267                         pun6_drop_party_ack_request(p, msg, cookie);
1268                         break;
1269                 }
1270                 VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
1271                     "Drop-party-ack.request in ps=%u", p->state);
1272                 uniapi_party_error(p, UNIAPI_ERROR_BAD_EPSTATE, cookie);
1273                 uni_msg_destroy(msg);
1274                 break;
1275
1276           case SIGP_STATUS_ENQUIRY_request:
1277                 /* Q.2971:Party-Control-U 12 */
1278                 /* Q.2971:Party-Control-N 12 */
1279                 punx_status_enquiry_request(p, cookie);
1280                 break;
1281
1282           /*
1283            * Timers
1284            */
1285           case SIGP_T397:
1286                 if (p->state == UNI_EPSTATE_ALERT_RCVD) {
1287                         /* Q.2971:Party-Control-U 7 (PU4) */
1288                         /* Q.2971:Party-Control-N 7 (PN4) */
1289                         pun4_t397(p);
1290                         break;
1291                 }
1292                 VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
1293                     "T397 in ps=%u", p->state);
1294                 break;
1295
1296           case SIGP_T398:
1297                 if (p->state == UNI_EPSTATE_DROP_INIT) {
1298                         /* Q.2971:Party-Control-U 10 (PU5) */
1299                         /* Q.2971:Party-Control-N 10 (PN5) */
1300                         pun5_t398(p);
1301                         break;
1302                 }
1303                 VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
1304                     "T398 in ps=%u", p->state);
1305                 break;
1306
1307           case SIGP_T399:
1308                 if (p->state == UNI_EPSTATE_ADD_INIT) {
1309                         /* Q.2971:Party-Control-U 4 (PU1) */
1310                         /* Q.2971:Party-Control-N 4 (PN1) */
1311                         pun1_t399(p);
1312                         break;
1313                 }
1314                 VERBOSE(p->call->uni, UNI_FAC_ERR, 1,
1315                     "T399 in ps=%u", p->state);
1316                 break;
1317
1318           case SIGP_END:
1319                 break;
1320         }
1321 }
1322
1323 static void
1324 t397_func(struct party *p)
1325 {
1326         uni_enq_party(p, SIGP_T397, 0, NULL, NULL);
1327 }
1328 static void
1329 t398_func(struct party *p)
1330 {
1331         uni_enq_party(p, SIGP_T398, 0, NULL, NULL);
1332 }
1333 static void
1334 t399_func(struct party *p)
1335 {
1336         uni_enq_party(p, SIGP_T399, 0, NULL, NULL);
1337 }
1338
1339 static int
1340 epstate_compat(struct party *p, enum uni_epstate state)
1341 {
1342         if (p->state == UNI_EPSTATE_ADD_INIT ||
1343             p->state == UNI_EPSTATE_ALERT_RCVD)
1344                 if (state == UNI_EPSTATE_ADD_INIT ||
1345                     state == UNI_EPSTATE_ALERT_RCVD)
1346                         return (0);
1347         if (p->state == UNI_EPSTATE_ADD_RCVD ||
1348             p->state == UNI_EPSTATE_ALERT_DLVD)
1349                 if (state == UNI_EPSTATE_ADD_RCVD ||
1350                     state == UNI_EPSTATE_ALERT_DLVD)
1351                         return (0);
1352         return (1);
1353 }