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 <[email protected]>
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
set_call_state(struct call * c,enum call_state state)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
map_callstate(enum call_state state)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 *
uni_find_call(struct uni * uni,struct uni_cref * cref)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 *
uni_find_callx(struct uni * uni,u_int cref,u_int mine)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 *
uni_create_call(struct uni * uni,u_int cref,u_int mine,uint32_t cookie)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 *
uni_create_new_call(struct uni * uni,uint32_t cookie)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
uni_destroy_call(struct call * c,int really)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
allocate_epref(struct call * c,struct uni_ie_epref * epref)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
reset_all_timers(struct call * c)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
clear_callD(struct call * c)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
un0_setup(struct call * c,struct uni_msg * m,struct uni_all * u,enum call_state new_state)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
un0_setup_request(struct call * c,struct uni_msg * m,uint32_t cookie,enum call_state new_state)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
u1n6_call_proc(struct call * c,struct uni_msg * m,struct uni_all * u,enum call_state new_state)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
u1n6_t303(struct call * c)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
u3n9_t310(struct call * c)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
u4n7_t301(struct call * c)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
unx_alerting(struct call * c,struct uni_msg * m,struct uni_all * u,enum call_state new_state)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
u6n1_proceeding_request(struct call * c,struct uni_msg * m,uint32_t cookie,enum call_state new_state)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
unx_alerting_request(struct call * c,struct uni_msg * m,uint32_t cookie,enum call_state new_state)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
unx_setup_response(struct call * c,struct uni_msg * m,uint32_t cookie,enum call_state new_state)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
n8_setup_compl_request(struct call * c,struct uni_msg * m,uint32_t cookie,enum call_state new_state)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
unx_connect(struct call * c,struct uni_msg * m,struct uni_all * u,enum call_state new_state)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
u8_t313(struct call * c)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
u8_connect_ack(struct call * c,struct uni_msg * m,struct uni_all * u,enum call_state new_state)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
n10_connect_ack(struct call * c,struct uni_msg * m,struct uni_all * u)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
unx_release_response(struct call * c,struct uni_msg * m,uint32_t cookie)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
uni_release_compl(struct call * c,struct uni_all * u)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
unx_release_compl(struct call * c,struct uni_msg * m,struct uni_all * u)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
unx_release(struct call * c,struct uni_msg * m,struct uni_all * u,enum call_state new_state)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
u11n12_release(struct call * c,struct uni_msg * m,struct uni_all * u)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
unx_notify(struct call * c,struct uni_msg * m,struct uni_all * u)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
unx_notify_request(struct call * c,struct uni_msg * m,uint32_t cookie)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
unx_release_request(struct call * c,struct uni_msg * m,uint32_t cookie,enum call_state new_state)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
respond_drop_party_ack(struct call * c,struct uni_ie_epref * epref,u_int cause)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
u11n12_t308(struct call * c)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
un11un12_status(struct call * c,struct uni_msg * m,struct uni_all * u)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
status_enq_filter(struct sig * sig,void * arg)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
unx_status(struct call * c,struct uni_msg * m,struct uni_all * u)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
unx_status_enquiry_request(struct call * c,struct uni_msg * msg,uint32_t cookie)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
unx_t322(struct call * c)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
unx_status_enq(struct call * c,struct uni_msg * m,struct uni_all * u)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
un10_link_release_indication(struct call * c)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
unx_link_release_indication(struct call * c)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
un10_link_establish_error_indication(struct call * c)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
call_se(struct call * c)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
un10_link_establish_indication(struct call * c)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
unx_link_establish_indication(struct call * c)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
un10_link_establish_confirm(struct call * c)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
unx_send_party_status_enq(struct call * c,struct uni_all * u)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
make_drop_cause(struct call * c,struct uni_ie_cause * cause)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
ux_drop_party_indication(struct call * c,struct uni_msg * api)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
nx_drop_party_indication(struct call * c,struct uni_msg * api)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
ux_drop_party_ack_indication(struct call * c,struct uni_msg * api)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
nx_drop_party_ack_indication(struct call * c,struct uni_msg * api)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
ux_add_party_rej_indication(struct call * c,struct uni_msg * api)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
nx_add_party_rej_indication(struct call * c,struct uni_msg * api)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
unx_add_party_request(struct call * c,struct uni_msg * msg,uint32_t cookie)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
un10_add_party_ack_request(struct call * c,struct uni_msg * msg,uint32_t cookie)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
unx_party_alerting_request(struct call * c,struct uni_msg * msg,uint32_t cookie)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
unx_add_party_rej_request(struct call * c,struct uni_msg * msg,uint32_t cookie)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
unx_drop_party_request(struct call * c,struct uni_msg * msg,uint32_t cookie)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
unx_drop_party_ack_request(struct call * c,struct uni_msg * msg,uint32_t cookie)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
unx_add_party(struct call * c,struct uni_msg * m,struct uni_all * u,int legal)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
un10n8_add_party_ack(struct call * c,struct uni_msg * m,struct uni_all * u,int legal)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
default_act_epref(struct uni * uni,struct uni_ie_epref * epref)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
unx_party_alerting(struct call * c,struct uni_msg * m,struct uni_all * u,int legal)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
handle_bad_drop_cause(struct call * c,struct uni_ie_cause * cause,int mkcause)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
unx_send_add_party_rej(struct call * c,struct uni_all * u)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
unx_add_party_rej(struct call * c,struct uni_msg * m,struct uni_all * u,int legal)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
unx_drop_party(struct call * c,struct uni_msg * m,struct uni_all * u,int legal)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
unx_drop_party_ack(struct call * c,struct uni_msg * m,struct uni_all * u,int legal)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
uni_bad_message(struct call * c,struct uni_all * u,u_int cause,struct uni_ie_epref * epref,int ps)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
unx_unknown(struct call * c,struct uni_msg * m,struct uni_all * u)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
uni_sig_call(struct call * c,enum call_sig sig,uint32_t cookie,struct uni_msg * msg,struct uni_all * u)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
t308_func(struct call * c)4225 t308_func(struct call *c)
4226 {
4227 	uni_enq_call(c, SIGC_T308, 0, NULL, NULL);
4228 }
4229 static void
t303_func(struct call * c)4230 t303_func(struct call *c)
4231 {
4232 	uni_enq_call(c, SIGC_T303, 0, NULL, NULL);
4233 }
4234 static void
t301_func(struct call * c)4235 t301_func(struct call *c)
4236 {
4237 	uni_enq_call(c, SIGC_T301, 0, NULL, NULL);
4238 }
4239 static void
t310_func(struct call * c)4240 t310_func(struct call *c)
4241 {
4242 	uni_enq_call(c, SIGC_T310, 0, NULL, NULL);
4243 }
4244 static void
t313_func(struct call * c)4245 t313_func(struct call *c)
4246 {
4247 	uni_enq_call(c, SIGC_T313, 0, NULL, NULL);
4248 }
4249 
4250 static void
t322_func(struct call * c)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
state_compat(struct call * c,enum uni_callstate peer)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 }
4311