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_coord.c,v 1.12 2004/08/05 07:11:01 brandt Exp $
30  *
31  * Coordinator
32  */
33 
34 #include <netnatm/unimsg.h>
35 #include <netnatm/saal/sscfudef.h>
36 #include <netnatm/msg/unistruct.h>
37 #include <netnatm/msg/unimsglib.h>
38 #include <netnatm/sig/uni.h>
39 
40 #include <netnatm/sig/unipriv.h>
41 #include <netnatm/sig/unimkmsg.h>
42 
43 #define STR(S) [S] = #S
44 static const char *const cunames[] = {
45 	STR(CU_STAT0),
46 	STR(CU_STAT1),
47 	STR(CU_STAT2),
48 	STR(CU_STAT3),
49 };
50 
51 #define DEF_PRIV_SIG(NAME, FROM)	[SIG##NAME] =	"SIG"#NAME,
52 static const char *const coord_sigs[] = {
53 	DEF_COORD_SIGS
54 };
55 #undef DEF_PRIV_SIG
56 
57 static void sig_all_calls(struct uni *, u_int sig);
58 static void set_custat(struct uni *, enum cu_stat);
59 
60 static void input_dummy(struct uni *uni, struct uni_msg *m, struct uni_all *u);
61 static void input_global(struct uni *uni, struct uni_msg *m, struct uni_all *u);
62 static void input_unknown(struct uni *uni, struct uni_msg *m, struct uni_all *u);
63 static void input_cobi(struct call *c, struct uni_msg *m, struct uni_all *u);
64 static void input_call(struct call *c, struct uni_msg *m, struct uni_all *u);
65 
TIMER_FUNC_UNI(t309,t309_func)66 TIMER_FUNC_UNI(t309, t309_func)
67 
68 /*
69  * All those 'bogus signal' printouts are not specified in the SDLs.
70  */
71 
72 
73 /*
74  * SAAL-ESTABLISH.indication
75  *
76  * This means either a resynchronisation or error-recovery or
77  * an incoming SSCOP connection.
78  */
79 static void
80 coord_saal_establish_indication(struct uni *uni)
81 {
82 	switch (uni->custat) {
83 
84 	  case CU_STAT0:	/* Q.2931:Coord-U 4/10 */
85 	  case CU_STAT3:	/* Q.2931:Coord-U 5/10 */
86 		sig_all_calls(uni, SIGC_LINK_ESTABLISH_indication);
87 		set_custat(uni, CU_STAT3);
88 		break;
89 
90 	  case CU_STAT1:
91 	  case CU_STAT2:
92 		VERBOSE0(uni, UNI_FAC_COORD,
93 		    "signal saal_establish.indication in CU%u", uni->custat);
94 		break;
95 
96 	  default:
97 		ASSERT(0, ("CU_STAT*"));
98 	}
99 }
100 
101 /*
102  * SAAL-ESTABLISH.confirm
103  */
104 static void
coord_saal_establish_confirm(struct uni * uni)105 coord_saal_establish_confirm(struct uni *uni)
106 {
107 	switch (uni->custat) {
108 
109 	  case CU_STAT0:
110 	  case CU_STAT2:
111 		VERBOSE0(uni, UNI_FAC_COORD,
112 		    "signal saal_establish.confirm in CU%u", uni->custat);
113 		break;
114 
115 	  case CU_STAT1:
116 		/*
117 		 * Q.2931:Co-ord-U 4/10
118 		 */
119 		TIMER_STOP_UNI(uni, t309);
120 		sig_all_calls(uni, SIGC_LINK_ESTABLISH_confirm);
121 		uni->funcs->uni_output(uni, uni->arg,
122 		    UNIAPI_LINK_ESTABLISH_confirm, 0, NULL);
123 		set_custat(uni, CU_STAT3);
124 		break;
125 
126 	  case CU_STAT3:
127 		/*
128 		 * Q.2931:Coord-U 5/10
129 		 */
130 		sig_all_calls(uni, SIGC_LINK_ESTABLISH_confirm);
131 		uni->funcs->uni_output(uni, uni->arg,
132 		    UNIAPI_LINK_ESTABLISH_confirm, 0, NULL);
133 		break;
134 
135 	  default:
136 		ASSERT(0, ("CU_STAT*"));
137 	}
138 }
139 
140 /*
141  * SAAL-RELEASE.confirm
142  */
143 static void
coord_saal_release_confirm(struct uni * uni)144 coord_saal_release_confirm(struct uni *uni)
145 {
146 	switch (uni->custat) {
147 
148 	  case CU_STAT0:
149 	  case CU_STAT1:
150 	  case CU_STAT3:
151 		VERBOSE0(uni, UNI_FAC_COORD,
152 		    "signal saal_release.confirm in CU%u", uni->custat);
153 		break;
154 
155 	  case CU_STAT2:
156 		/*
157 		 * Q.2931:Coord-U 5/10
158 		 */
159 		uni->funcs->uni_output(uni, uni->arg,
160 		    UNIAPI_LINK_RELEASE_confirm, 0, NULL);
161 		set_custat(uni, CU_STAT0);
162 		break;
163 
164 	  default:
165 		ASSERT(0, ("CU_STAT*"));
166 	}
167 }
168 
169 /*
170  * SAAL failure.
171  */
172 static void
coord_saal_release_indication(struct uni * uni)173 coord_saal_release_indication(struct uni *uni)
174 {
175 	switch (uni->custat) {
176 
177 	  case CU_STAT0:
178 	  case CU_STAT2:
179 		VERBOSE0(uni, UNI_FAC_COORD,
180 		    "signal saal_release.indication in CU%u", uni->custat);
181 		break;
182 
183 	  case CU_STAT1:
184 	  case CU_STAT3:
185 		/*
186 		 * Q.2931:Coord-U 4/10
187 		 * Q.2931:Coord-U 5/10
188 		 */
189 		sig_all_calls(uni, SIGC_LINK_RELEASE_indication);
190 		set_custat(uni, CU_STAT0);
191 		break;
192 
193 	  default:
194 		ASSERT(0, ("CU_STAT*"));
195 	}
196 }
197 
198 /*
199  * Link-establish.request from USER. This can also come from
200  * a call instance. In this case 'cookie' is zero.
201  */
202 static void
coord_link_establish_request(struct uni * uni,uint32_t cookie)203 coord_link_establish_request(struct uni *uni, uint32_t cookie)
204 {
205 	switch (uni->custat) {
206 
207 	  case CU_STAT0:
208 		/*
209 		 * Q.2931:Coord-U 4/10
210 		 */
211 		uni->funcs->saal_output(uni, uni->arg,
212 		    SAAL_ESTABLISH_request, NULL);
213 		if (!TIMER_ISACT(uni, t309))
214 			TIMER_START_UNI(uni, t309, uni->timer309);
215 		set_custat(uni, CU_STAT1);
216 		if (cookie)
217 			uniapi_uni_error(uni, UNIAPI_OK, cookie, 0);
218 		break;
219 
220 	  case CU_STAT1:
221 		/*
222 		 * Q.2931:Coord-U 4/10
223 		 * This is probably missing from the delay field.
224 		 */
225 		uni_delenq_coord(uni, SIGO_LINK_ESTABLISH_request,
226 		    cookie, NULL);
227 		break;
228 
229 	  case CU_STAT2:
230 		uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0);
231 		if (cookie == 0)
232 			VERBOSE0(uni, UNI_FAC_COORD,
233 			    "signal link-establish.request in CU%u",
234 			    uni->custat);
235 		break;
236 
237 	  case CU_STAT3:
238 		/*
239 		 * Q.2931:Coord-U 5/10
240 		 */
241 		uni->funcs->uni_output(uni, uni->arg,
242 		    UNIAPI_LINK_ESTABLISH_confirm, 0, NULL);
243 		uniapi_uni_error(uni, UNIAPI_OK, cookie, 0);
244 		break;
245 
246 	  default:
247 		ASSERT(0, ("CU_STAT*"));
248 	}
249 }
250 
251 /*
252  * Link-release.request from user
253  */
254 static void
coord_link_release_request(struct uni * uni,u_int cookie)255 coord_link_release_request(struct uni *uni, u_int cookie)
256 {
257 	switch (uni->custat) {
258 
259 	  case CU_STAT0:
260 	  case CU_STAT1:
261 	  case CU_STAT2:
262 		uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0);
263 		break;
264 
265 	  case CU_STAT3:
266 		/*
267 		 * Q.2931:Coord-U 5/10
268 		 */
269 		uni->funcs->saal_output(uni, uni->arg,
270 		    SAAL_RELEASE_request, NULL);
271 		set_custat(uni, CU_STAT2);
272 		uniapi_uni_error(uni, UNIAPI_OK, cookie, 0);
273 		break;
274 
275 	  default:
276 		ASSERT(0, ("CU_STAT*"));
277 	}
278 }
279 
280 /*
281  * T309 timeout signal
282  */
283 static void
coord_t309(struct uni * uni)284 coord_t309(struct uni *uni)
285 {
286 	switch (uni->custat) {
287 
288 	  case CU_STAT0:
289 	  case CU_STAT1:
290 		/*
291 		 * Q.2931:Coord-U 4/10
292 		 */
293 		sig_all_calls(uni, SIGC_LINK_ESTABLISH_ERROR_indication);
294 		set_custat(uni, CU_STAT0);
295 		/* this is not in the SDLs, but how will the call control
296 		 * know, that starting the LINK has failed otherwise? */
297 		uni->funcs->uni_output(uni, uni->arg,
298 		    UNIAPI_LINK_RELEASE_confirm, 0, NULL);
299 		break;
300 
301 	  case CU_STAT2:
302 	  case CU_STAT3:
303 		VERBOSE0(uni, UNI_FAC_COORD,
304 		    "signal T309 in CU%u", uni->custat);
305 		break;
306 
307 	  default:
308 		ASSERT(0, ("CU_STAT*"));
309 	}
310 }
311 
312 /*
313  * Message from SAAL
314  */
315 static void
coord_saal_data_indication(struct uni * uni,struct uni_msg * m)316 coord_saal_data_indication(struct uni *uni, struct uni_msg *m)
317 {
318 	struct uni_all *u;
319 	struct call *c;
320 
321 	memset(&uni->cause, 0, sizeof(uni->cause));
322 	if ((u = UNI_ALLOC()) == NULL) {
323 		uni_msg_destroy(m);
324 		return;
325 	}
326 	if (uni_decode_head(m, u, &uni->cx)) {
327 		VERBOSE(uni, UNI_FAC_COORD, 2, "bogus message - ignored");
328 		uni_msg_destroy(m);
329 		UNI_FREE(u);
330 		return;
331 	}
332 	if (u->u.hdr.cref.cref == CREF_DUMMY) {
333 		if (uni->cx.q2932) {
334 			input_dummy(uni, m, u);
335 		} else {
336 			VERBOSE(uni, UNI_FAC_COORD, 2, "dummy cref - ignored");
337 			UNI_FREE(u);
338 			uni_msg_destroy(m);
339 		}
340 		return;
341 	}
342 
343 	if (u->u.hdr.cref.cref == CREF_GLOBAL)
344 		input_global(uni, m, u);
345 	else if ((c = uni_find_call(uni, &u->u.hdr.cref)) == NULL)
346 		input_unknown(uni, m, u);
347 	else if (c->type == CALL_COBI)
348 		input_cobi(c, m, u);
349 	else
350 		input_call(c, m, u);
351 }
352 
353 /*
354  * Message with global call reference
355  *
356  * Q.2931:Coord-U (X) 7/10
357  */
358 static void
input_global(struct uni * uni,struct uni_msg * m,struct uni_all * u)359 input_global(struct uni *uni, struct uni_msg *m, struct uni_all *u)
360 {
361 	VERBOSE(uni, UNI_FAC_COORD, 2, "GLOB MTYPE = %x", u->mtype);
362 
363 	switch (u->mtype) {
364 
365 	  default:
366 		/*
367 		 * Q.2931:Coord-U 7/10
368 		 * Q.2931: 5.6.3.2e
369 		 * Amd4:   29e
370 		 */
371 		uni_respond_status(uni, &u->u.hdr.cref,
372 		    u->u.hdr.cref.flag ? uni->glob_start : uni->glob_respond,
373 		    UNI_CAUSE_CREF_INV);
374 		break;
375 
376 	  case UNI_RESTART:
377 		if (u->u.hdr.cref.flag) {
378 			/*
379 			 * Q.2931:Coord-U 7/10 (5.6.3.2h)
380 			 */
381 			uni_respond_status(uni, &u->u.hdr.cref,
382 			    uni->glob_start, UNI_CAUSE_CREF_INV);
383 			break;
384 		}
385 		uni_enq_resp(uni, SIGR_RESTART, 0, m, u);
386 		return;
387 
388 	  case UNI_RESTART_ACK:
389 		if (!u->u.hdr.cref.flag) {
390 			/*
391 			 * Q.2931:Coord-U 7/10 (5.6.3.2h)
392 			 * Note, that the SDL diagram contains an error.
393 			 * The error with the 'YES' label should go to the
394 			 * box below 'OTHER'.
395 			 */
396 			uni_respond_status(uni, &u->u.hdr.cref,
397 			    uni->glob_respond, UNI_CAUSE_CREF_INV);
398 			break;
399 		}
400 		uni_enq_start(uni, SIGS_RESTART_ACK, 0, m, u);
401 		return;
402 
403 	  case UNI_STATUS:
404 		if (u->u.hdr.cref.flag)
405 			uni_enq_start(uni, SIGS_STATUS, 0, m, u);
406 		else
407 			uni_enq_resp(uni, SIGR_STATUS, 0, m, u);
408 		return;
409 	}
410 	uni_msg_destroy(m);
411 	UNI_FREE(u);
412 }
413 
414 /*
415  * Q.2931:Coord-U 8/10
416  *
417  * Message for an unknown call reference
418  */
419 static void
input_unknown(struct uni * uni,struct uni_msg * m,struct uni_all * u)420 input_unknown(struct uni *uni, struct uni_msg *m, struct uni_all *u)
421 {
422 	struct uni_all *resp;
423 	struct call *c;
424 	u_int cause = UNI_CAUSE_CREF_INV;
425 
426 	VERBOSE(uni, UNI_FAC_COORD, 2, "UNKNOWN MTYPE = %x", u->mtype);
427 
428 	switch (u->mtype) {
429 
430 	  default:
431 		/*
432 		 * This message type is entirly unknown
433 		 *
434 		 * 5.6.4 and 5.7.1 are only when the call is not in the
435 		 * NULL state. This means, 5.6.3.2a takes over.
436 		 */
437 		break;
438 
439 	  case UNI_SETUP:
440 		if (u->u.hdr.cref.flag)
441 			/*
442 			 * 5.6.3.2c
443 			 */
444 			goto drop;
445 		if ((c = uni_create_call(uni, u->u.hdr.cref.cref, 0, 0)) != NULL) {
446 			uni_enq_call(c, SIGC_SETUP, 0, m, u);
447 			return;
448 		}
449 		goto drop;
450 
451 	  case UNI_RELEASE_COMPL:
452 		/*
453 		 * 5.6.3.2c
454 		 */
455 		goto drop;
456 
457 	  case UNI_STATUS:
458 		/*
459 		 * 5.6.12
460 		 *
461 		 * The SDLs don't use the verify procedure and don't
462 		 * handle the case of an invalid callstate - we
463 		 * ignore the message, if the callstate is not good.
464 		 */
465 		(void)uni_decode_body(m, u, &uni->cx);
466 		if (!IE_ISGOOD(u->u.status.callstate))
467 			goto drop;
468 		if (u->u.status.callstate.state == UNI_CALLSTATE_U0)
469 			goto drop;
470 		cause = UNI_CAUSE_MSG_INCOMP;
471 		break;
472 
473 	  case UNI_STATUS_ENQ:
474 		if ((resp = UNI_ALLOC()) == NULL)
475 			goto drop;
476 
477 		(void)uni_decode_body(m, u, &uni->cx);
478 		MK_MSG_RESP(resp, UNI_STATUS, &u->u.hdr.cref);
479 		MK_IE_CALLSTATE(resp->u.status.callstate, UNI_CALLSTATE_U0);
480 		MK_IE_CAUSE(resp->u.status.cause, UNI_CAUSE_LOC_USER,
481 		    UNI_CAUSE_STATUS);
482 
483 		if (IE_ISGOOD(u->u.status_enq.epref)) {
484 			/* reflect epref as required by L3MU_PO */
485 			resp->u.status.epref = u->u.status_enq.epref;
486 			MK_IE_EPREF(resp->u.status.epref,
487 			    u->u.status_enq.epref.epref,
488 			    !u->u.status_enq.epref.flag);
489 			MK_IE_EPSTATE(resp->u.status.epstate, UNI_EPSTATE_NULL);
490 		}
491 
492 		(void)uni_send_output(resp, uni);
493 
494 		UNI_FREE(resp);
495 		goto drop;
496 
497 	  case UNI_COBISETUP:
498 		if (u->u.hdr.cref.flag)
499 			/*
500 			 * 5.6.3.2c (probably)
501 			 */
502 			goto drop;
503 		if ((c = uni_create_call(uni, u->u.hdr.cref.cref, 0, 0)) != NULL) {
504 			uni_enq_call(c, SIGC_COBISETUP, 0, m, u);
505 			return;
506 		}
507 		goto drop;
508 	}
509 
510 	/*
511 	 * 5.6.3.2a)
512 	 *
513 	 * Respond with a RELEASE COMPLETE
514 	 */
515 	if ((resp = UNI_ALLOC()) == NULL)
516 		goto drop;
517 
518 	MK_MSG_RESP(resp, UNI_RELEASE_COMPL, &u->u.hdr.cref);
519 	MK_IE_CAUSE(resp->u.release_compl.cause[0], UNI_CAUSE_LOC_USER, cause);
520 	if (uni_diag(cause, UNI_CODING_ITU) == UNI_DIAG_MTYPE)
521 		ADD_CAUSE_MTYPE(resp->u.release_compl.cause[0], u->mtype);
522 
523 	(void)uni_send_output(resp, uni);
524 
525 	UNI_FREE(resp);
526 
527   drop:
528 	UNI_FREE(u);
529 	uni_msg_destroy(m);
530 }
531 
532 static void
input_cobi(struct call * c __unused,struct uni_msg * m,struct uni_all * u)533 input_cobi(struct call *c __unused, struct uni_msg *m, struct uni_all *u)
534 {
535 	/* XXX */
536 	UNI_FREE(u);
537 	uni_msg_destroy(m);
538 }
539 
540 static void
input_dummy(struct uni * uni __unused,struct uni_msg * m,struct uni_all * u)541 input_dummy(struct uni *uni __unused, struct uni_msg *m, struct uni_all *u)
542 {
543 	/* XXX */
544 	UNI_FREE(u);
545 	uni_msg_destroy(m);
546 }
547 
548 static void
input_call(struct call * c,struct uni_msg * m,struct uni_all * u)549 input_call(struct call *c, struct uni_msg *m, struct uni_all *u)
550 {
551 	VERBOSE(c->uni, UNI_FAC_COORD, 2, "CALL MTYPE = %x %d/%s",
552 		u->mtype, c->cref, c->mine ? "mine":"his");
553 
554 	switch (u->mtype) {
555 
556 	  case UNI_SETUP:
557 		/*
558 		 * Ignored
559 		 */
560 		break;
561 
562 	  case UNI_CALL_PROC:
563 		uni_enq_call(c, SIGC_CALL_PROC, 0, m, u);
564 		return;
565 
566 	  case UNI_ALERTING:
567 		uni_enq_call(c, SIGC_ALERTING, 0, m, u);
568 		return;
569 
570 	  case UNI_RELEASE:
571 		uni_enq_call(c, SIGC_RELEASE, 0, m, u);
572 		return;
573 
574 	  case UNI_RELEASE_COMPL:
575 		uni_enq_call(c, SIGC_RELEASE_COMPL, 0, m, u);
576 		return;
577 
578 	  case UNI_CONNECT:
579 		uni_enq_call(c, SIGC_CONNECT, 0, m, u);
580 		return;
581 
582 	  case UNI_CONNECT_ACK:
583 		uni_enq_call(c, SIGC_CONNECT_ACK, 0, m, u);
584 		return;
585 
586 	  case UNI_NOTIFY:
587 		uni_enq_call(c, SIGC_NOTIFY, 0, m, u);
588 		return;
589 
590 	  case UNI_STATUS:
591 		uni_enq_call(c, SIGC_STATUS, 0, m, u);
592 		return;
593 
594 	  case UNI_STATUS_ENQ:
595 		uni_enq_call(c, SIGC_STATUS_ENQ, 0, m, u);
596 		return;
597 
598 	  case UNI_ADD_PARTY:
599 		uni_enq_call(c, SIGC_ADD_PARTY, 0, m, u);
600 		return;
601 
602 	  case UNI_PARTY_ALERTING:
603 		uni_enq_call(c, SIGC_PARTY_ALERTING, 0, m, u);
604 		return;
605 
606 	  case UNI_ADD_PARTY_ACK:
607 		uni_enq_call(c, SIGC_ADD_PARTY_ACK, 0, m, u);
608 		return;
609 
610 	  case UNI_ADD_PARTY_REJ:
611 		uni_enq_call(c, SIGC_ADD_PARTY_REJ, 0, m, u);
612 		return;
613 
614 	  case UNI_DROP_PARTY:
615 		uni_enq_call(c, SIGC_DROP_PARTY, 0, m, u);
616 		return;
617 
618 	  case UNI_DROP_PARTY_ACK:
619 		uni_enq_call(c, SIGC_DROP_PARTY_ACK, 0, m, u);
620 		return;
621 
622 	  default:
623 		uni_enq_call(c, SIGC_UNKNOWN, 0, m, u);
624 		return;
625 	}
626 	UNI_FREE(u);
627 	uni_msg_destroy(m);
628 }
629 
630 
631 /*
632  * This macro tries to implement the delaying behaviour for
633  * message from the API when we are in the Awaiting-Establish state.
634  * In this state, the message is delayed. If we drop back to CU 0,
635  * everything gets unqueued and errors are returned for all that stuff.
636  * If we progess to CUSTAT2 we process the requests.
637  */
638 #define COMMON_DELAY(SIG, COOKIE)					\
639 		if (uni->custat == CU_STAT0 || uni->custat == CU_STAT2) {\
640 			uniapi_uni_error(uni, UNIAPI_ERROR_BADCU,	\
641 			    COOKIE, 0);					\
642 			break;						\
643 		}							\
644 		if (uni->custat == CU_STAT1) {				\
645 			uni_delenq_coord(uni, SIG, COOKIE, msg);	\
646 			break;						\
647 		}
648 
649 /*
650  * Signal handler of the coordinator
651  */
652 void
uni_sig_coord(struct uni * uni,enum coord_sig sig,uint32_t cookie,struct uni_msg * msg)653 uni_sig_coord(struct uni *uni, enum coord_sig sig, uint32_t cookie,
654     struct uni_msg *msg)
655 {
656 	struct call *c;
657 
658 	if (sig >= SIGO_END) {
659 		VERBOSE(uni, UNI_FAC_ERR, 1, "Signal %d outside of range to "
660 		    "Coord", sig);
661 		if (msg)
662 			uni_msg_destroy(msg);
663 		return;
664 	}
665 
666 	VERBOSE(uni, UNI_FAC_COORD, 1, "Signal %s in state %s",
667 	    coord_sigs[sig], cunames[uni->custat]);
668 
669 	switch (sig) {
670 
671 	  case SIGO_END:
672 		break;
673 
674 	  case SIGO_DATA:	/* delayed output */
675 		if (uni->custat == CU_STAT0 || uni->custat == CU_STAT1)
676 			break;	/* drop */
677 		if (uni->custat == CU_STAT1)
678 			uni_delenq_coord(uni, SIGO_DATA, cookie, msg);/* ??? */
679 		else
680 			uni->funcs->saal_output(uni, uni->arg,
681 			    SAAL_DATA_request, msg);
682 		msg = NULL;
683 		break;
684 
685 	  /*
686 	   * SAAL signals
687 	   */
688 	  case SIGO_SAAL_ESTABLISH_indication:
689 		coord_saal_establish_indication(uni);
690 		break;
691 
692 	  case SIGO_SAAL_ESTABLISH_confirm:
693 		coord_saal_establish_confirm(uni);
694 		break;
695 
696 	  case SIGO_SAAL_RELEASE_confirm:
697 		coord_saal_release_confirm(uni);
698 		break;
699 
700 	  case SIGO_SAAL_RELEASE_indication:
701 		coord_saal_release_indication(uni);
702 		break;
703 
704 	  case SIGO_SAAL_DATA_indication:
705 		coord_saal_data_indication(uni, msg);
706 		msg = NULL;
707 		break;
708 
709 	  case SIGO_SAAL_UDATA_indication:
710 		VERBOSE0(uni, UNI_FAC_ERR, "SAAL_UDATA_indication");
711 		break;
712 
713 	  /*
714 	   * Signals from USER
715 	   */
716 	  case SIGO_LINK_ESTABLISH_request:
717 		coord_link_establish_request(uni, cookie);
718 		break;
719 
720 	  case SIGO_LINK_RELEASE_request:
721 		coord_link_release_request(uni, cookie);
722 		break;
723 
724 	  case SIGO_RESET_request:
725 		uni_enq_start(uni, SIGS_RESET_request, cookie, msg, NULL);
726 		msg = NULL;
727 		if (uni->custat == CU_STAT0) {
728 			uni->funcs->saal_output(uni, uni->arg,
729 			    SAAL_ESTABLISH_request, NULL);
730 			if (!TIMER_ISACT(uni, t309))
731 				TIMER_START_UNI(uni, t309, uni->timer309);
732 			set_custat(uni, CU_STAT1);
733 		}
734 		break;
735 
736 	  case SIGO_RESET_ERROR_response:
737 		COMMON_DELAY(SIGO_RESET_ERROR_response, cookie);
738 		uni_enq_resp(uni, SIGR_RESET_ERROR_response, cookie, msg, NULL);
739 		msg = NULL;
740 		break;
741 
742 	  case SIGO_RESET_response:
743 		COMMON_DELAY(SIGO_RESET_response, cookie);
744 		uni_enq_resp(uni, SIGR_RESET_response, cookie, msg, NULL);
745 		msg = NULL;
746 		break;
747 
748 	  case SIGO_SETUP_request:
749 		if ((c = uni_create_new_call(uni, cookie)) != NULL) {
750 			uni_enq_call(c, SIGC_SETUP_request, cookie, msg, NULL);
751 			msg = NULL;
752 			if (uni->custat == CU_STAT0) {
753 				uni->funcs->saal_output(uni, uni->arg,
754 				    SAAL_ESTABLISH_request, NULL);
755 				if (!TIMER_ISACT(uni, t309))
756 					TIMER_START_UNI(uni, t309, uni->timer309);
757 				set_custat(uni, CU_STAT1);
758 			}
759 		} else {
760 			uniapi_uni_error(uni, UNIAPI_ERROR_NOMEM, cookie,
761 			    UNI_CALLSTATE_U0);
762 		}
763 		break;
764 
765 	  case SIGO_PROCEEDING_request:
766 	    {
767 		struct uniapi_proceeding_request *arg =
768 		    uni_msg_rptr(msg, struct uniapi_proceeding_request *);
769 
770 		COMMON_DELAY(SIGO_PROCEEDING_request, cookie);
771 		if ((c = uni_find_call(uni, &arg->call_proc.hdr.cref)) != NULL) {
772 			uni_enq_call(c, SIGC_PROCEEDING_request, cookie, msg, NULL);
773 			msg = NULL;
774 		} else {
775 			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
776 			    UNI_CALLSTATE_U0);
777 		}
778 		break;
779 	    }
780 
781 	  case SIGO_ALERTING_request:
782 	    {
783 		struct uniapi_alerting_request *arg =
784 		    uni_msg_rptr(msg, struct uniapi_alerting_request *);
785 
786 		COMMON_DELAY(SIGO_ALERTING_request, cookie);
787 		if ((c = uni_find_call(uni, &arg->alerting.hdr.cref)) != NULL) {
788 			uni_enq_call(c, SIGC_ALERTING_request, cookie, msg, NULL);
789 			msg = NULL;
790 		} else {
791 			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
792 			    UNI_CALLSTATE_U0);
793 		}
794 		break;
795 	    }
796 
797 	  case SIGO_SETUP_response:
798 	    {
799 		struct uniapi_setup_response *arg =
800 		    uni_msg_rptr(msg, struct uniapi_setup_response *);
801 
802 		COMMON_DELAY(SIGO_SETUP_response, cookie);
803 		if ((c = uni_find_call(uni, &arg->connect.hdr.cref)) != NULL) {
804 			uni_enq_call(c, SIGC_SETUP_response, cookie, msg, NULL);
805 			msg = NULL;
806 		} else {
807 			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
808 			    UNI_CALLSTATE_U0);
809 		}
810 		break;
811 	    }
812 
813 	  case SIGO_SETUP_COMPLETE_request:
814 	    {
815 		struct uniapi_setup_complete_request *arg =
816 		    uni_msg_rptr(msg, struct uniapi_setup_complete_request *);
817 
818 		COMMON_DELAY(SIGO_SETUP_COMPLETE_request, cookie);
819 		if ((c = uni_find_call(uni, &arg->connect_ack.hdr.cref)) != NULL) {
820 			uni_enq_call(c, SIGC_SETUP_COMPLETE_request,
821 			    cookie, msg, NULL);
822 			msg = NULL;
823 		} else {
824 			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
825 			    UNI_CALLSTATE_U0);
826 		}
827 		break;
828 	    }
829 
830 	  case SIGO_RELEASE_request:
831 	    {
832 		struct uniapi_release_request *arg =
833 		    uni_msg_rptr(msg, struct uniapi_release_request *);
834 
835 		COMMON_DELAY(SIGO_RELEASE_request, cookie);
836 		if ((c = uni_find_call(uni, &arg->release.hdr.cref)) != NULL) {
837 			uni_enq_call(c, SIGC_RELEASE_request, cookie, msg, NULL);
838 			msg = NULL;
839 		} else {
840 			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
841 			    UNI_CALLSTATE_U0);
842 		}
843 		break;
844 	    }
845 
846 	  case SIGO_RELEASE_response:
847 	    {
848 		struct uniapi_release_response *arg =
849 		    uni_msg_rptr(msg, struct uniapi_release_response *);
850 
851 		COMMON_DELAY(SIGO_RELEASE_response, cookie);
852 		if ((c = uni_find_call(uni, &arg->release_compl.hdr.cref)) != NULL) {
853 			uni_enq_call(c, SIGC_RELEASE_response, cookie, msg, NULL);
854 			msg = NULL;
855 		} else {
856 			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
857 			    UNI_CALLSTATE_U0);
858 		}
859 		break;
860 	    }
861 
862 	  case SIGO_NOTIFY_request:
863 	    {
864 		struct uniapi_notify_request *arg =
865 		    uni_msg_rptr(msg, struct uniapi_notify_request *);
866 
867 		COMMON_DELAY(SIGO_NOTIFY_request, cookie);
868 		if ((c = uni_find_call(uni, &arg->notify.hdr.cref)) != NULL) {
869 			uni_enq_call(c, SIGC_NOTIFY_request, cookie, msg, NULL);
870 			msg = NULL;
871 		} else {
872 			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
873 			    UNI_CALLSTATE_U0);
874 		}
875 		break;
876 	    }
877 
878 	  case SIGO_STATUS_ENQUIRY_request:
879 	    {
880 		struct uniapi_status_enquiry_request *arg =
881 		    uni_msg_rptr(msg, struct uniapi_status_enquiry_request *);
882 
883 		COMMON_DELAY(SIGO_STATUS_ENQUIRY_request, cookie);
884 		if ((c = uni_find_call(uni, &arg->cref)) != NULL) {
885 			uni_enq_call(c, SIGC_STATUS_ENQUIRY_request, cookie, msg, NULL);
886 			msg = NULL;
887 		} else {
888 			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
889 			    UNI_CALLSTATE_U0);
890 		}
891 		break;
892 	    }
893 
894 	  case SIGO_ADD_PARTY_request:
895 	    {
896 		struct uniapi_add_party_request *arg =
897 		    uni_msg_rptr(msg, struct uniapi_add_party_request *);
898 
899 		COMMON_DELAY(SIGO_ADD_PARTY_request, cookie);
900 		if ((c = uni_find_call(uni, &arg->add.hdr.cref)) != NULL) {
901 			if (c->type != CALL_ROOT) {
902 				uniapi_call_error(c, UNIAPI_ERROR_BAD_CTYPE,
903 				    cookie);
904 				break;
905 			}
906 			uni_enq_call(c, SIGC_ADD_PARTY_request, cookie, msg, NULL);
907 			msg = NULL;
908 		} else {
909 			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
910 			    UNI_CALLSTATE_U0);
911 		}
912 		break;
913 	    }
914 
915 	  case SIGO_PARTY_ALERTING_request:
916 	    {
917 		struct uniapi_party_alerting_request *arg =
918 		    uni_msg_rptr(msg, struct uniapi_party_alerting_request *);
919 
920 		COMMON_DELAY(SIGO_PARTY_ALERTING_request, cookie);
921 		if ((c = uni_find_call(uni, &arg->alert.hdr.cref)) != NULL) {
922 			if (c->type != CALL_LEAF) {
923 				uniapi_call_error(c, UNIAPI_ERROR_BAD_CTYPE,
924 				    cookie);
925 				break;
926 			}
927 			uni_enq_call(c, SIGC_PARTY_ALERTING_request, cookie, msg, NULL);
928 			msg = NULL;
929 		} else {
930 			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
931 			    UNI_CALLSTATE_U0);
932 		}
933 		break;
934 	    }
935 
936 	  case SIGO_ADD_PARTY_ACK_request:
937 	    {
938 		struct uniapi_add_party_ack_request *arg =
939 		    uni_msg_rptr(msg, struct uniapi_add_party_ack_request *);
940 
941 		COMMON_DELAY(SIGO_ADD_PARTY_ACK_request, cookie);
942 		if ((c = uni_find_call(uni, &arg->ack.hdr.cref)) != NULL) {
943 			if (c->type != CALL_LEAF) {
944 				uniapi_call_error(c, UNIAPI_ERROR_BAD_CTYPE,
945 				    cookie);
946 				break;
947 			}
948 			uni_enq_call(c, SIGC_ADD_PARTY_ACK_request, cookie, msg, NULL);
949 			msg = NULL;
950 		} else {
951 			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
952 			    UNI_CALLSTATE_U0);
953 		}
954 		break;
955 	    }
956 
957 	  case SIGO_ADD_PARTY_REJ_request:
958 	    {
959 		struct uniapi_add_party_rej_request *arg =
960 		    uni_msg_rptr(msg, struct uniapi_add_party_rej_request *);
961 
962 		COMMON_DELAY(SIGO_ADD_PARTY_REJ_request, cookie);
963 		if ((c = uni_find_call(uni, &arg->rej.hdr.cref)) != NULL) {
964 			if (c->type != CALL_LEAF) {
965 				uniapi_call_error(c, UNIAPI_ERROR_BAD_CTYPE,
966 				    cookie);
967 				break;
968 			}
969 			uni_enq_call(c, SIGC_ADD_PARTY_REJ_request, cookie, msg, NULL);
970 			msg = NULL;
971 		} else {
972 			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
973 			    UNI_CALLSTATE_U0);
974 		}
975 		break;
976 	    }
977 
978 	  case SIGO_DROP_PARTY_request:
979 	    {
980 		struct uniapi_drop_party_request *arg =
981 		    uni_msg_rptr(msg, struct uniapi_drop_party_request *);
982 
983 		COMMON_DELAY(SIGO_DROP_PARTY_request, cookie);
984 		if ((c = uni_find_call(uni, &arg->drop.hdr.cref)) != NULL) {
985 			if (c->type != CALL_ROOT && c->type != CALL_LEAF) {
986 				uniapi_call_error(c, UNIAPI_ERROR_BAD_CTYPE,
987 				    cookie);
988 				break;
989 			}
990 			uni_enq_call(c, SIGC_DROP_PARTY_request, cookie, msg, NULL);
991 			msg = NULL;
992 		} else {
993 			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
994 			    UNI_CALLSTATE_U0);
995 		}
996 		break;
997 	    }
998 
999 	  case SIGO_DROP_PARTY_ACK_request:
1000 	    {
1001 		struct uniapi_drop_party_ack_request *arg =
1002 		    uni_msg_rptr(msg, struct uniapi_drop_party_ack_request *);
1003 
1004 		COMMON_DELAY(SIGO_DROP_PARTY_ACK_request, cookie);
1005 		if ((c = uni_find_call(uni, &arg->ack.hdr.cref)) != NULL) {
1006 			if (c->type != CALL_ROOT && c->type != CALL_LEAF) {
1007 				uniapi_call_error(c, UNIAPI_ERROR_BAD_CTYPE,
1008 				    cookie);
1009 				break;
1010 			}
1011 			uni_enq_call(c, SIGC_DROP_PARTY_ACK_request, cookie, msg, NULL);
1012 			msg = NULL;
1013 		} else {
1014 			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
1015 			    UNI_CALLSTATE_U0);
1016 		}
1017 		break;
1018 	    }
1019 
1020 	  case SIGO_ABORT_CALL_request:
1021 	    {
1022 		struct uniapi_abort_call_request *arg =
1023 		    uni_msg_rptr(msg, struct uniapi_abort_call_request *);
1024 
1025 		if ((c = uni_find_call(uni, &arg->cref)) != NULL) {
1026 			uni_enq_call(c, SIGC_ABORT_CALL_request, cookie, NULL, NULL);
1027 		} else {
1028 			uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALL, cookie,
1029 			    UNI_CALLSTATE_U0);
1030 		}
1031 		break;
1032 	    }
1033 
1034 	  /*
1035 	   * Call-Control
1036 	   */
1037 	  case SIGO_CALL_DESTROYED:
1038 		uni->funcs->uni_output(uni, uni->arg,
1039 		    UNIAPI_CALL_DESTROYED, 0, msg);
1040 		msg = NULL;
1041 		break;
1042 
1043 	  /*
1044 	   * ResetRespond
1045 	   */
1046 	  case SIGO_RESET_indication:
1047 		uni->funcs->uni_output(uni, uni->arg,
1048 		    UNIAPI_RESET_indication, 0, msg);
1049 		msg = NULL;
1050 		break;
1051 
1052 	  /*
1053 	   * Timeouts
1054 	   */
1055 	  case SIGO_T309:
1056 		coord_t309(uni);
1057 		break;
1058 
1059 	}
1060 	if (msg != NULL)
1061 		uni_msg_destroy(msg);
1062 }
1063 
1064 /*
1065  * Send a signal to all call instances
1066  */
1067 static void
sig_all_calls(struct uni * uni,u_int sig)1068 sig_all_calls(struct uni *uni, u_int sig)
1069 {
1070 	struct call *call;
1071 
1072 	TAILQ_FOREACH(call, &uni->calls, link)
1073 		uni_enq_call(call, sig, 0, NULL, NULL);
1074 }
1075 
1076 /*
1077  * Set a new coordinator state - this moves all delayed coordinator
1078  * signals from the delayed queue to the signal queue.
1079  */
1080 static int
cufilt(struct sig * s,void * arg __unused)1081 cufilt(struct sig *s, void *arg __unused)
1082 {
1083 	return (s->type == SIG_COORD);
1084 }
1085 
1086 static void
set_custat(struct uni * uni,enum cu_stat nstate)1087 set_custat(struct uni *uni, enum cu_stat nstate)
1088 {
1089 	if (uni->custat != nstate) {
1090 		uni->custat = nstate;
1091 		uni_undel(uni, cufilt, NULL);
1092 	}
1093 }
1094 
1095 /*
1096  * T309 timeout function
1097  */
1098 static void
t309_func(struct uni * uni)1099 t309_func(struct uni *uni)
1100 {
1101 	uni_enq_coord(uni, SIGO_T309, 0, NULL);
1102 }
1103 
1104 /*
1105  * Respond with a status message
1106  */
1107 void
uni_respond_status(struct uni * uni,struct uni_cref * cref,enum uni_callstate cs,enum uni_cause c1)1108 uni_respond_status(struct uni *uni, struct uni_cref *cref,
1109     enum uni_callstate cs, enum uni_cause c1)
1110 {
1111 	struct uni_all *resp;
1112 
1113 	if ((resp = UNI_ALLOC()) == NULL)
1114 		return;
1115 
1116 	MK_MSG_RESP(resp, UNI_STATUS, cref);
1117 	MK_IE_CALLSTATE(resp->u.status.callstate, cs);
1118 	MK_IE_CAUSE(resp->u.status.cause, UNI_CAUSE_LOC_USER, c1);
1119 
1120 	(void)uni_send_output(resp, uni);
1121 
1122 	UNI_FREE(resp);
1123 }
1124 
1125 /*
1126  * Respond with a status message
1127  */
1128 void
uni_respond_status_mtype(struct uni * uni,struct uni_cref * cref,enum uni_callstate cs,enum uni_cause c1,u_int mtype)1129 uni_respond_status_mtype(struct uni *uni, struct uni_cref *cref,
1130     enum uni_callstate cs, enum uni_cause c1, u_int mtype)
1131 {
1132 	struct uni_all *resp;
1133 
1134 	if((resp = UNI_ALLOC()) == NULL)
1135 		return;
1136 
1137 	MK_MSG_RESP(resp, UNI_STATUS, cref);
1138 	MK_IE_CALLSTATE(resp->u.status.callstate, cs);
1139 	MK_IE_CAUSE(resp->u.status.cause, UNI_CAUSE_LOC_USER, c1);
1140 	ADD_CAUSE_MTYPE(resp->u.status.cause, mtype);
1141 
1142 	(void)uni_send_output(resp, uni);
1143 
1144 	UNI_FREE(resp);
1145 }
1146 
1147 /*
1148  * Send a message. If we are in CUSTAT1, delay the message if we
1149  * are in CUSTAT3 send it, else drop it.
1150  */
1151 int
uni_send_output(struct uni_all * u,struct uni * uni)1152 uni_send_output(struct uni_all *u, struct uni *uni)
1153 {
1154 	struct uni_msg *m;
1155 	int err;
1156 
1157 	if (uni->custat == CU_STAT0 || uni->custat == CU_STAT2)
1158 		return (0);
1159 
1160 	m = uni_msg_alloc(1024);
1161 	if ((err = uni_encode(m, u, &uni->cx)) != 0) {
1162 		VERBOSE0(uni, UNI_FAC_ERR, "uni_encode failed: %08x", err);
1163 		uni_msg_destroy(m);
1164 		return (-1);
1165 	}
1166 	if (uni->custat == CU_STAT1)
1167 		uni_delenq_coord(uni, SIGO_DATA, 0, m);
1168 	else
1169 		uni->funcs->saal_output(uni, uni->arg, SAAL_DATA_request, m);
1170 	return (0);
1171 }
1172