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
44static void drop_partyE(struct party *p);
45static int epstate_compat(struct party *, enum uni_epstate);
46
47#define DEF_PRIV_SIG(NAME, FROM)	[SIG##NAME] =	"SIG"#NAME,
48static const char *const party_sigs[] = {
49	DEF_PARTY_SIGS
50};
51#undef DEF_PRIV_SIG
52
53TIMER_FUNC_PARTY(t397, t397_func)
54TIMER_FUNC_PARTY(t398, t398_func)
55TIMER_FUNC_PARTY(t399, t399_func)
56
57static __inline void
58set_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 */
73struct party *
74uni_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
117struct party *
118uni_create_party(struct call *c, struct uni_ie_epref *epref)
119{
120	return (uni_create_partyx(c, epref->epref, epref->flag, 0));
121}
122
123struct party *
124uni_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}
134struct party *
135uni_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 */
150void
151uni_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 */
189u_int
190uni_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
219static void
220stop_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 */
234static void
235pun0_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 */
268static void
269punx_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 */
297static void
298pun2_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 */
328static void
329pun0_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 */
353static void
354pun2_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 */
384static void
385pun1_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 */
420static void
421pun1pun4_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 */
456static void
457pun1_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 */
487static void
488pun5_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 */
522static void
523punx_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 */
550static void
551punx_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 */
589static void
590pun5_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 */
629static void
630pun1_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 */
650static void
651pun5_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 */
695static void
696pun4_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 */
714static void
715drop_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 */
753static void
754punx_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 */
786static void
787pun6_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 */
816static void
817punx_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 */
839static void
840punx_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 */
887static void
888pun5_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
913void
914uni_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
1323static void
1324t397_func(struct party *p)
1325{
1326	uni_enq_party(p, SIGP_T397, 0, NULL, NULL);
1327}
1328static void
1329t398_func(struct party *p)
1330{
1331	uni_enq_party(p, SIGP_T398, 0, NULL, NULL);
1332}
1333static void
1334t399_func(struct party *p)
1335{
1336	uni_enq_party(p, SIGP_T399, 0, NULL, NULL);
1337}
1338
1339static int
1340epstate_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}
1354