1 /*
2 * Copyright (c) 1996-2003
3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * Author: Hartmut Brandt <harti@freebsd.org>
28 *
29 * $Begemot: libunimsg/netnatm/sig/sig_call.c,v 1.65 2004/08/05 07:11:00 brandt Exp $
30 *
31 * Call instance handling
32 *
33 * Note:
34 * In all functions that handle messages from the user or from
35 * the SAAL, commit memory allocation always at the begin of the
36 * function. If allocation fails, ignore saal messages and
37 * respond with an error to user messages.
38 */
39
40 #include <netnatm/unimsg.h>
41 #include <netnatm/saal/sscfudef.h>
42 #include <netnatm/msg/unistruct.h>
43 #include <netnatm/msg/unimsglib.h>
44 #include <netnatm/sig/uni.h>
45
46 #include <netnatm/sig/unipriv.h>
47 #include <netnatm/sig/unimkmsg.h>
48 #include <netnatm/sig/unimsgcpy.h>
49
50 static enum call_state state_compat(struct call *, enum uni_callstate);
51 static void respond_drop_party_ack(struct call *, struct uni_ie_epref *, u_int);
52
53
54 #define DEF_PRIV_SIG(NAME, FROM) [SIG##NAME] = "SIG"#NAME,
55 static const char *const call_sigs[] = {
56 DEF_CALL_SIGS
57 };
58 #undef DEF_PRIV_SIG
59
60 TIMER_FUNC_CALL(t308, t308_func)
61 TIMER_FUNC_CALL(t303, t303_func)
62 TIMER_FUNC_CALL(t301, t301_func)
63 TIMER_FUNC_CALL(t310, t310_func)
64 TIMER_FUNC_CALL(t313, t313_func)
65 TIMER_FUNC_CALL(t322, t322_func)
66
67 const struct callstates callstates[] = {
68 [CALLST_NULL] = { "NU0", UNI_CALLSTATE_U0 },
69 [CALLST_U1] = { "U1", UNI_CALLSTATE_U1 },
70 [CALLST_U3] = { "U3", UNI_CALLSTATE_U3 },
71 [CALLST_U4] = { "U4", UNI_CALLSTATE_U4 },
72 [CALLST_U6] = { "U6", UNI_CALLSTATE_U6 },
73 [CALLST_U7] = { "U7", UNI_CALLSTATE_U7 },
74 [CALLST_U8] = { "U8", UNI_CALLSTATE_U8 },
75 [CALLST_U9] = { "U9", UNI_CALLSTATE_U9 },
76 [CALLST_U10] = { "U10", UNI_CALLSTATE_U10 },
77 [CALLST_U11] = { "U11", UNI_CALLSTATE_U11 },
78 [CALLST_U12] = { "U12", UNI_CALLSTATE_U12 },
79 [CALLST_N1] = { "N1", UNI_CALLSTATE_N1 },
80 [CALLST_N3] = { "N3", UNI_CALLSTATE_N3 },
81 [CALLST_N4] = { "N4", UNI_CALLSTATE_N4 },
82 [CALLST_N6] = { "N6", UNI_CALLSTATE_N6 },
83 [CALLST_N7] = { "N7", UNI_CALLSTATE_N7 },
84 [CALLST_N8] = { "N8", UNI_CALLSTATE_N8 },
85 [CALLST_N9] = { "N9", UNI_CALLSTATE_N9 },
86 [CALLST_N10] = { "N10", UNI_CALLSTATE_N10 },
87 [CALLST_N11] = { "N11", UNI_CALLSTATE_N11 },
88 [CALLST_N12] = { "N12", UNI_CALLSTATE_N12 },
89 };
90
91 static void unx_send_add_party_rej(struct call *c, struct uni_all *u);
92
93 static __inline void
94 set_call_state(struct call *c, enum call_state state)
95 {
96 ASSERT(state == CALLST_NULL ||
97 (c->uni->proto == UNIPROTO_UNI40U &&
98 (state >= CALLST_U1 && state <= CALLST_U12)) ||
99 (c->uni->proto == UNIPROTO_UNI40N &&
100 (state >= CALLST_N1 && state <= CALLST_N12)),
101 ("setting wrong callstate for proto %u: %u", c->uni->proto, state));
102
103 if (c->cstate != state) {
104 VERBOSE(c->uni, UNI_FAC_CALL, 1, "call %d/%d %s -> %s",
105 c->cref, c->mine, callstates[c->cstate].name,
106 callstates[state].name);
107 c->cstate = state;
108 }
109 }
110
111 static enum uni_callstate
112 map_callstate(enum call_state state)
113 {
114 return (callstates[state].ext);
115 }
116
117 /*
118 * Find the call. Assume, that the cref is one of a message just received.
119 * That is, if the call reference flag is 0 it is his call, if it is 1 it
120 * is my call.
121 */
122 struct call *
123 uni_find_call(struct uni *uni, struct uni_cref *cref)
124 {
125 struct call *c;
126
127 TAILQ_FOREACH(c, &uni->calls, link)
128 if (c->cref == cref->cref && (!c->mine == !cref->flag))
129 return (c);
130 return (NULL);
131 }
132 struct call *
133 uni_find_callx(struct uni *uni, u_int cref, u_int mine)
134 {
135 struct call *c;
136
137 TAILQ_FOREACH(c, &uni->calls, link)
138 if (c->cref == cref && !c->mine == !mine)
139 return (c);
140 return (NULL);
141 }
142
143 /*
144 * Create a new call instance. The type must be set by the caller.
145 */
146 struct call *
147 uni_create_call(struct uni *uni, u_int cref, u_int mine, uint32_t cookie)
148 {
149 struct call *c;
150 struct uniapi_call_created *ind;
151 struct uni_msg *api;
152
153 if ((c = CALL_ALLOC()) == NULL)
154 return (NULL);
155
156 if ((ind = ALLOC_API(struct uniapi_call_created, api)) == NULL) {
157 CALL_FREE(c);
158 return (NULL);
159 }
160 ind->cref.cref = cref;
161 ind->cref.flag = mine;
162
163 c->uni = uni;
164 c->type = CALL_NULL;
165 c->cref = cref;
166 c->mine = mine;
167 c->cstate = CALLST_NULL;
168 TAILQ_INIT(&c->parties);
169
170 TIMER_INIT_CALL(c, t301);
171 TIMER_INIT_CALL(c, t303);
172 TIMER_INIT_CALL(c, t308);
173 TIMER_INIT_CALL(c, t310);
174 TIMER_INIT_CALL(c, t313);
175 TIMER_INIT_CALL(c, t322);
176
177 TAILQ_INSERT_HEAD(&uni->calls, c, link);
178
179 uni->funcs->uni_output(uni, uni->arg, UNIAPI_CALL_CREATED, cookie, api);
180
181 VERBOSE(c->uni, UNI_FAC_CALL, 1, "created call %u/%s",
182 c->cref, c->mine ? "mine" : "his");
183
184 return (c);
185 }
186
187 struct call *
188 uni_create_new_call(struct uni *uni, uint32_t cookie)
189 {
190 struct call *c;
191 uint32_t old = uni->cref_alloc++;
192
193 again:
194 if (uni->cref_alloc == (1 << 23))
195 uni->cref_alloc = 1;
196 if (uni->cref_alloc == old)
197 return (NULL); /* all crefs exhausted!!! */
198 TAILQ_FOREACH(c, &uni->calls, link)
199 if (c->mine && c->cref == uni->cref_alloc) {
200 uni->cref_alloc++;
201 goto again;
202 }
203 return (uni_create_call(uni, uni->cref_alloc, 1, cookie));
204 }
205
206 /*
207 * Assume timers are all stopped. Memory is not actually freed unless
208 * the reference count drops to 0.
209 * This function is assumed to remove the call from the parent UNI's
210 * call queue.
211 */
212 void
213 uni_destroy_call(struct call *c, int really)
214 {
215 struct uniapi_call_destroyed *ind;
216 struct uni_msg *api;
217 struct party *p;
218
219 VERBOSE(c->uni, UNI_FAC_CALL, 1, "destroying call %u/%s",
220 c->cref, c->mine ? "mine" : "his");
221
222 TIMER_DESTROY_CALL(c, t301);
223 TIMER_DESTROY_CALL(c, t303);
224 TIMER_DESTROY_CALL(c, t308);
225 TIMER_DESTROY_CALL(c, t310);
226 TIMER_DESTROY_CALL(c, t313);
227 TIMER_DESTROY_CALL(c, t322);
228 TAILQ_REMOVE(&c->uni->calls, c, link);
229
230 uni_delsig(c->uni, SIG_CALL, c, NULL);
231
232 while ((p = TAILQ_FIRST(&c->parties)) != NULL) {
233 TAILQ_REMOVE(&c->parties, p, link);
234 uni_destroy_party(p, really);
235 }
236
237 if (!really) {
238 ind = ALLOC_API(struct uniapi_call_destroyed, api);
239 if (ind != NULL) {
240 ind->cref.cref = c->cref;
241 ind->cref.flag = c->mine;
242
243 uni_enq_coord(c->uni, SIGO_CALL_DESTROYED, 0, api);
244 }
245
246 uni_enq_call(c, SIGC_CALL_DELETE, 0, NULL, NULL);
247 return;
248 }
249
250 CALL_FREE(c);
251 }
252
253 static void
254 allocate_epref(struct call *c, struct uni_ie_epref *epref)
255 {
256 struct party *p;
257 uint32_t old = c->epref_alloc++;
258
259 again:
260 if (c->epref_alloc == (1 << 15))
261 c->epref_alloc = 0;
262 if (c->epref_alloc == old)
263 return; /* all crefs exhausted!!! */
264 TAILQ_FOREACH(p, &c->parties, link)
265 if (p->epref == c->epref_alloc) {
266 c->epref_alloc++;
267 goto again;
268 }
269 IE_SETPRESENT(*epref);
270 epref->flag = 0;
271 epref->epref = c->epref_alloc;
272
273 epref->h.coding = UNI_CODING_ITU;
274 epref->h.act = UNI_IEACT_DEFAULT;
275 }
276
277 static void
278 reset_all_timers(struct call *c)
279 {
280 TIMER_STOP_CALL(c, t301);
281 TIMER_STOP_CALL(c, t303);
282 TIMER_STOP_CALL(c, t308);
283 TIMER_STOP_CALL(c, t310);
284 TIMER_STOP_CALL(c, t313);
285 TIMER_STOP_CALL(c, t322);
286 }
287
288 /*
289 * Initiate call clearing because of a problem. This is label D in
290 * the SDLs and is called from many places.
291 * The call must have constructed the cause IE in struct call.
292 *
293 * Q.2971:Call-Control-U 27/39
294 * Q.2971:Call-Control-N 28/39
295 *
296 * Memory problems are handled differently here: we simply ignore them
297 * by not sending messages or user indications. Because of T308 we
298 * may be lucky to send the message in a second run.
299 *
300 * It is assumed, that the cause for the release is constructed by
301 * the calling function in uni->cause.
302 */
303 static void
304 clear_callD(struct call *c)
305 {
306 struct uni_msg *api;
307 struct uniapi_release_indication *ind;
308 struct party *p;
309 struct uni_all *rel;
310
311 /*
312 * Send indication to API
313 */
314 if ((ind = ALLOC_API(struct uniapi_release_indication, api)) != NULL) {
315 ind->release.hdr.cref.cref = c->cref;
316 ind->release.hdr.cref.flag = c->mine;
317 ind->release.hdr.act = UNI_MSGACT_DEFAULT;
318 ind->release.cause[0] = c->uni->cause;
319
320 c->uni->funcs->uni_output(c->uni, c->uni->arg,
321 UNIAPI_RELEASE_indication, 0, api);
322 }
323
324 reset_all_timers(c);
325
326 if (c->type == CALL_LEAF || c->type == CALL_ROOT) {
327 TAILQ_FOREACH(p, &c->parties, link) {
328 uni_enq_party(p, SIGP_RELEASE_request, 0, NULL, NULL);
329 }
330 }
331
332 memset(&c->msg_release, 0, sizeof(c->msg_release));
333 c->msg_release.cause[0] = c->uni->cause;
334
335 if ((rel = UNI_ALLOC()) != NULL) {
336 rel->u.release = c->msg_release;
337 MK_MSG_ORIG(rel, UNI_RELEASE, c->cref, !c->mine);
338 (void)uni_send_output(rel, c->uni);
339 UNI_FREE(rel);
340 }
341
342 TIMER_START_CALL(c, t308, c->uni->timer308);
343 c->cnt308 = 0;
344
345 if (c->uni->proto == UNIPROTO_UNI40N)
346 set_call_state(c, CALLST_N12);
347 else
348 set_call_state(c, CALLST_U11);
349 }
350
351
352 /**********************************************************************/
353 /*
354 * SETUP message in state NULL
355 *
356 * Q.2971:Call-Control-U 4/39
357 * Q.2971:Call-Control-N 4/39
358 */
359 static void
360 un0_setup(struct call *c, struct uni_msg *m, struct uni_all *u,
361 enum call_state new_state)
362 {
363 struct uni_all *resp;
364 struct party *p;
365 struct uniapi_setup_indication *ind;
366 struct uni_msg *api;
367 enum verify v;
368
369 if ((ind = ALLOC_API(struct uniapi_setup_indication, api)) == NULL) {
370 clear:
371 uni_destroy_call(c, 0);
372 uni_msg_destroy(m);
373 UNI_FREE(u);
374 return;
375 }
376
377 /*
378 * Analyze message
379 */
380 (void)uni_decode_body(m, u, &c->uni->cx);
381 MANDATE_IE(c->uni, u->u.setup.bearer, UNI_IE_BEARER);
382 MANDATE_IE(c->uni, u->u.setup.traffic, UNI_IE_TRAFFIC);
383 MANDATE_IE(c->uni, u->u.setup.called, UNI_IE_CALLED);
384
385 /*
386 * UNI4.0: 9.1.1.2 Notes 2/3
387 */
388 if (!IE_ISPRESENT(u->u.setup.qos))
389 MANDATE_IE(c->uni, u->u.setup.exqos, UNI_IE_EXQOS);
390 if (!IE_ISPRESENT(u->u.setup.exqos))
391 MANDATE_IE(c->uni, u->u.setup.qos, UNI_IE_QOS);
392
393 /*
394 * Q.2971
395 */
396 if (IE_ISGOOD(u->u.setup.bearer) &&
397 u->u.setup.bearer.cfg == UNI_BEARER_MP) {
398 if (IE_ISGOOD(u->u.setup.epref) &&
399 u->u.setup.epref.flag == 1) {
400 IE_SETERROR(u->u.setup.epref);
401 (void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF,
402 u->u.setup.epref.h.act, UNI_IERR_BAD);
403 }
404 uni_mandate_epref(c->uni, &u->u.setup.epref);
405 }
406
407 v = uni_verify(c->uni, u->u.hdr.act);
408 switch (v) {
409
410 case VFY_RAI:
411 uni_respond_status_verify(c->uni, &u->u.hdr.cref,
412 UNI_CALLSTATE_U0, NULL, 0);
413 /* FALLTHRU */
414 case VFY_I:
415 uni_msg_destroy(api);
416 goto clear;
417
418 case VFY_RAIM:
419 case VFY_CLR:
420 if ((resp = UNI_ALLOC()) != NULL) {
421 MK_MSG_RESP(resp, UNI_RELEASE_COMPL, &u->u.hdr.cref);
422 uni_vfy_collect_ies(c->uni);
423 resp->u.release_compl.cause[0] = c->uni->cause;
424 uni_send_output(resp, c->uni);
425 UNI_FREE(resp);
426 }
427 uni_msg_destroy(api);
428 goto clear;
429
430 case VFY_RAP:
431 case VFY_RAPU:
432 uni_respond_status_verify(c->uni, &u->u.hdr.cref,
433 map_callstate(new_state), NULL, 0);
434 /* FALLTHRU */
435 case VFY_OK:
436 break;
437 }
438
439 if (u->u.setup.bearer.cfg == UNI_BEARER_P2P) {
440 c->type = CALL_P2P;
441
442 } else {
443 c->type = CALL_LEAF;
444 if ((p = uni_create_party(c, &u->u.setup.epref)) == NULL) {
445 uni_msg_destroy(api);
446 goto clear;
447 }
448 uni_enq_party(p, SIGP_SETUP, 0, NULL, NULL);
449 }
450
451 ind->setup.hdr = u->u.hdr;
452 copy_msg_setup(&u->u.setup, &ind->setup);
453 c->uni->funcs->uni_output(c->uni, c->uni->arg,
454 UNIAPI_SETUP_indication, 0, api);
455
456 uni_msg_destroy(m);
457 UNI_FREE(u);
458
459 set_call_state(c, new_state);
460 }
461
462 /*
463 * Setup.request from user
464 *
465 * Q.2971:Call-Control-U 4/39 (U0)
466 * Q.2971:Call-Control-N 4/39 (N0)
467 */
468 static void
469 un0_setup_request(struct call *c, struct uni_msg *m, uint32_t cookie,
470 enum call_state new_state)
471 {
472 struct uniapi_setup_request *arg =
473 uni_msg_rptr(m, struct uniapi_setup_request *);
474 struct uni_setup *setup = &arg->setup;
475 struct uni_all *out;
476 struct party *p;
477
478 if (!IE_ISGOOD(setup->bearer)) {
479 uni_msg_destroy(m);
480 uniapi_call_error(c, UNIAPI_ERROR_MISSING_IE, cookie);
481 uni_destroy_call(c, 0);
482 return;
483 }
484 if ((out = UNI_ALLOC()) == NULL) {
485 uni_msg_destroy(m);
486 uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
487 uni_destroy_call(c, 0);
488 return;
489 }
490
491 c->msg_setup = *setup;
492
493 if (IE_ISGOOD(setup->connid))
494 c->connid = setup->connid;
495
496 if (setup->bearer.cfg == UNI_BEARER_P2P) {
497 c->type = CALL_P2P;
498 } else {
499 c->type = CALL_ROOT;
500
501 /*
502 * If the user didn't specify a endpoint reference,
503 * use 0. Use IE_IGNORE accoring to Appendix II Q.2971
504 */
505 if (!IE_ISPRESENT(c->msg_setup.epref)) {
506 MK_IE_EPREF(c->msg_setup.epref, 0, 0);
507 if (c->uni->proto == UNIPROTO_UNI40N)
508 c->msg_setup.epref.h.act = UNI_IEACT_IGNORE;
509
510 } else if (!IE_ISGOOD(c->msg_setup.epref)) {
511 uni_msg_destroy(m);
512 uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
513 uni_destroy_call(c, 0);
514 return;
515 }
516 if ((p = uni_create_partyx(c, 0, 1, cookie)) == NULL) {
517 uni_msg_destroy(m);
518 uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
519 uni_destroy_call(c, 0);
520 return;
521 }
522 uni_enq_party(p, SIGP_SETUP_request, cookie, NULL, NULL);
523 }
524
525 uni_msg_destroy(m);
526
527 out->u.setup = c->msg_setup;
528 MK_MSG_ORIG(out, UNI_SETUP, c->cref, !c->mine);
529 (void)uni_send_output(out, c->uni);
530 UNI_FREE(out);
531
532 TIMER_START_CALL(c, t303, c->uni->timer303);
533 c->cnt303 = 0;
534
535 set_call_state(c, new_state);
536
537 uniapi_call_error(c, UNIAPI_OK, cookie);
538 }
539
540 /*
541 * CALL PROCEEDING message
542 *
543 * Q.2971:Call-Control-U 6/39 (in U1)
544 * Q.2971:Call-Control-N 11/39 (in N6)
545 */
546 static void
547 u1n6_call_proc(struct call *c, struct uni_msg *m, struct uni_all *u,
548 enum call_state new_state)
549 {
550 struct uni_call_proc *cp = &u->u.call_proc;
551 struct uniapi_proceeding_indication *ind;
552 struct uni_msg *api;
553
554 ind = ALLOC_API(struct uniapi_proceeding_indication, api);
555 if (ind == NULL) {
556 ignore:
557 uni_msg_destroy(m);
558 UNI_FREE(u);
559 return;
560 }
561 /*
562 * Analyze message
563 */
564 (void)uni_decode_body(m, u, &c->uni->cx);
565 if (!IE_ISPRESENT(c->connid) && !IE_ISGOOD(cp->connid))
566 uni_mandate_ie(c->uni, UNI_IE_CONNID);
567
568 /*
569 * Q.2971: L3MU_01_03 requests us to ignore the message if
570 * the EPREF is missing.
571 */
572 if (c->msg_setup.bearer.cfg == UNI_BEARER_MP &&
573 IE_ISPRESENT(c->msg_setup.epref)) {
574 if (!IE_ISPRESENT(cp->epref))
575 uni_mandate_ie(c->uni, UNI_IE_EPREF); \
576
577 else if (IE_ISGOOD(cp->epref) &&
578 (cp->epref.flag != 1 ||
579 cp->epref.epref != c->msg_setup.epref.epref)) {
580 IE_SETERROR(cp->epref);
581 (void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF,
582 cp->epref.h.act, UNI_IERR_BAD);
583 }
584 }
585
586 switch (uni_verify(c->uni, u->u.hdr.act)) {
587
588 case VFY_CLR:
589 uni_vfy_collect_ies(c->uni);
590 clear_callD(c);
591 /* FALLTHRU */
592 case VFY_I:
593 uni_msg_destroy(api);
594 goto ignore;
595
596 case VFY_RAIM:
597 case VFY_RAI:
598 report:
599 uni_respond_status_verify(c->uni, &u->u.hdr.cref,
600 map_callstate(c->cstate), NULL, 0);
601 uni_msg_destroy(api);
602 goto ignore;
603
604 case VFY_RAP:
605 case VFY_RAPU:
606 if (c->type == CALL_ROOT && !IE_ISGOOD(cp->epref))
607 goto report;
608 uni_respond_status_verify(c->uni, &u->u.hdr.cref,
609 map_callstate(new_state), NULL, 0);
610 /* FALLTHRU */
611 case VFY_OK:
612 break;
613 }
614
615 TIMER_STOP_CALL(c, t303);
616
617 if (IE_ISGOOD(cp->connid))
618 c->connid = cp->connid;
619
620 ind->call_proc.hdr = u->u.hdr;
621 copy_msg_call_proc(cp, &ind->call_proc);
622 c->uni->funcs->uni_output(c->uni, c->uni->arg,
623 UNIAPI_PROCEEDING_indication, 0, api);
624
625 TIMER_START_CALL(c, t310, c->uni->timer310);
626
627 uni_msg_destroy(m);
628 UNI_FREE(u);
629
630 set_call_state(c, new_state);
631 }
632
633 /*
634 * T303 tick.
635 *
636 * Q.2971:Call-Control-U 6/39
637 * Q.2971:Call-Control-N 11/39
638 */
639 static void
640 u1n6_t303(struct call *c)
641 {
642 struct uni_all *msg;
643 struct uniapi_release_confirm *conf;
644 struct uni_msg *api;
645
646 VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T303 tick %d",
647 c->cref, c->mine ? "mine" : "his", c->cnt303 + 1);
648
649 if (++c->cnt303 < c->uni->init303) {
650 if ((msg = UNI_ALLOC()) != NULL) {
651 msg->u.setup = c->msg_setup;
652 MK_MSG_ORIG(msg, UNI_SETUP, c->cref, !c->mine);
653 (void)uni_send_output(msg, c->uni);
654 UNI_FREE(msg);
655 }
656 TIMER_START_CALL(c, t303, c->uni->timer303);
657 return;
658 }
659
660 /*
661 * Send indication to API
662 */
663 if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) != NULL) {
664 conf->release.hdr.cref.cref = c->cref;
665 conf->release.hdr.cref.flag = c->mine;
666 conf->release.hdr.act = UNI_MSGACT_DEFAULT;
667 MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER,
668 UNI_CAUSE_NO_RESPONSE);
669
670 c->uni->funcs->uni_output(c->uni, c->uni->arg,
671 UNIAPI_RELEASE_confirm, 0, api);
672 }
673
674 /*
675 * send to party (there may be only one)
676 */
677 if (c->type == CALL_ROOT && !TAILQ_EMPTY(&c->parties)) {
678 uni_enq_party(TAILQ_FIRST(&c->parties),
679 SIGP_RELEASE_confirm, 0, NULL, NULL);
680 }
681 uni_destroy_call(c, 0);
682 }
683
684 /*
685 * T310 (Call Proceeding) timer tick.
686 *
687 * Q.2971:Call-Control-U 7/39
688 * Q.2971:Call-Control-N 17/39
689 */
690 static void
691 u3n9_t310(struct call *c)
692 {
693 VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T310 tick",
694 c->cref, c->mine ? "mine" : "his");
695
696 MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_NO_RESPONSE);
697 clear_callD(c);
698 }
699
700 /*
701 * T301 (Alerting) timer tick.
702 *
703 * Q.2971:Call-Control-U Missing
704 * Q.2971:Call-Control-N 14/39
705 */
706 static void
707 u4n7_t301(struct call *c)
708 {
709 VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T301 tick",
710 c->cref, c->mine ? "mine" : "his");
711
712 MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_NO_RESP_ALERT);
713 clear_callD(c);
714 }
715
716 /*
717 * ALERTING received
718 *
719 * Q.2971:Call-Control-U 37/39 (U1)
720 * Q.2971:Call-Control-U 7/39 (U3)
721 * Q.2971:Call-Control-N 9/39 (N6)
722 * Q.2971:Call-Control-N 17/39 (N9)
723 *
724 * There are two errors in the user side SDL Annex A:
725 *
726 * - the resetted timers are swapped (T310 and T303)
727 *
728 * - for U1 we should go to C12, not C3 to start T301.
729 */
730 static void
731 unx_alerting(struct call *c, struct uni_msg *m, struct uni_all *u,
732 enum call_state new_state)
733 {
734 struct uni_alerting *al = &u->u.alerting;
735 struct uniapi_alerting_indication *ind;
736 struct uni_msg *api;
737
738 ind = ALLOC_API(struct uniapi_alerting_indication, api);
739 if (ind == NULL) {
740 ignore:
741 uni_msg_destroy(m);
742 UNI_FREE(u);
743 return;
744 }
745
746 /*
747 * Analyze message
748 */
749 (void)uni_decode_body(m, u, &c->uni->cx);
750 if (!IE_ISPRESENT(c->connid) && !IE_ISGOOD(al->connid))
751 uni_mandate_ie(c->uni, UNI_IE_CONNID);
752
753 /*
754 * Q.2971: L3MU_01_04 requests us to ignore the message if the
755 * EPREF is missing.
756 */
757 if (c->msg_setup.bearer.cfg == UNI_BEARER_MP &&
758 IE_ISPRESENT(c->msg_setup.epref)) {
759 if (!IE_ISPRESENT(al->epref))
760 uni_mandate_ie(c->uni, UNI_IE_EPREF); \
761
762 else if (IE_ISGOOD(al->epref) &&
763 (al->epref.flag != 1 ||
764 al->epref.epref != c->msg_setup.epref.epref)) {
765 IE_SETERROR(al->epref);
766 (void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF,
767 al->epref.h.act, UNI_IERR_BAD);
768 }
769 }
770
771 switch (uni_verify(c->uni, u->u.hdr.act)) {
772
773 case VFY_CLR:
774 uni_vfy_collect_ies(c->uni);
775 clear_callD(c);
776 case VFY_I:
777 uni_msg_destroy(api);
778 goto ignore;
779
780 case VFY_RAIM:
781 case VFY_RAI:
782 report:
783 uni_respond_status_verify(c->uni, &u->u.hdr.cref,
784 map_callstate(c->cstate), NULL, 0);
785 uni_msg_destroy(api);
786 goto ignore;
787
788 case VFY_RAP:
789 case VFY_RAPU:
790 if (c->type == CALL_ROOT && !IE_ISGOOD(al->epref))
791 goto report;
792 uni_respond_status_verify(c->uni, &u->u.hdr.cref,
793 map_callstate(c->cstate), NULL, 0);
794 case VFY_OK:
795 break;
796 }
797
798 if (c->cstate == CALLST_U1 || c->cstate == CALLST_N6)
799 TIMER_STOP_CALL(c, t303);
800 else if (c->cstate == CALLST_U3 || c->cstate == CALLST_N9)
801 TIMER_STOP_CALL(c, t310);
802
803 if (IE_ISGOOD(al->connid))
804 c->connid = al->connid;
805
806 ind->alerting.hdr = u->u.hdr;
807 copy_msg_alerting(al, &ind->alerting);
808
809 if (c->type == CALL_LEAF || c->type == CALL_ROOT) {
810 uni_enq_party(TAILQ_FIRST(&c->parties), SIGP_ALERTING,
811 0, NULL, NULL);
812 c->uni->funcs->uni_output(c->uni, c->uni->arg,
813 UNIAPI_ALERTING_indication, 0, api);
814 } else {
815 c->uni->funcs->uni_output(c->uni, c->uni->arg,
816 UNIAPI_ALERTING_indication, 0, api);
817 TIMER_START_CALL(c, t301, c->uni->timer301);
818 }
819 UNI_FREE(u);
820 uni_msg_destroy(m);
821
822 set_call_state(c, new_state);
823 }
824
825 /*
826 * Proceeding.request from API
827 *
828 * Q.2971:Call-Control-U 12/39 (U6)
829 * Q.2971:Call-Control-N 6/39 (N1)
830 */
831 static void
832 u6n1_proceeding_request(struct call *c, struct uni_msg *m, uint32_t cookie,
833 enum call_state new_state)
834 {
835 struct uni_all *msg;
836 struct uniapi_proceeding_request *arg =
837 uni_msg_rptr(m, struct uniapi_proceeding_request *);
838
839 if ((msg = UNI_ALLOC()) == NULL) {
840 uni_msg_destroy(m);
841 uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
842 return;
843 }
844
845 if (IE_ISGOOD(arg->call_proc.connid))
846 c->connid = arg->call_proc.connid;
847
848 msg->u.call_proc = arg->call_proc;
849 MK_MSG_ORIG(msg, UNI_CALL_PROC, c->cref, !c->mine);
850 (void)uni_send_output(msg, c->uni);
851 UNI_FREE(msg);
852
853 set_call_state(c, new_state);
854
855 uni_msg_destroy(m);
856
857 uniapi_call_error(c, UNIAPI_OK, cookie);
858 }
859
860 /*
861 * Alerting.request from API
862 *
863 * Q.2971:Call-Control-U 13/39 (U6)
864 * Q.2971:Call-Control-U 17/39 (U9)
865 * Q.2971:Call-Control-N 38/39 (N1)
866 * Q.2971:Call-Control-N 7/39 (N3)
867 */
868 static void
869 unx_alerting_request(struct call *c, struct uni_msg *m, uint32_t cookie,
870 enum call_state new_state)
871 {
872 struct uni_all *msg;
873 struct uniapi_alerting_request *arg =
874 uni_msg_rptr(m, struct uniapi_alerting_request *);
875
876 if ((msg = UNI_ALLOC()) == NULL) {
877 uni_msg_destroy(m);
878 uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
879 return;
880 }
881
882 if (c->type == CALL_ROOT || c->type == CALL_LEAF) {
883 uni_enq_party(TAILQ_FIRST(&c->parties),
884 SIGP_ALERTING_request, cookie, NULL, NULL);
885 }
886
887 /*
888 * It's not really clear, what happens, if we send another
889 * connid in CALL_PROC and ALERTING
890 */
891 if (!IE_ISGOOD(c->connid) && IE_ISGOOD(arg->alerting.connid))
892 c->connid = arg->alerting.connid;
893
894 msg->u.alerting = arg->alerting;
895 MK_MSG_ORIG(msg, UNI_ALERTING, c->cref, !c->mine);
896 (void)uni_send_output(msg, c->uni);
897 UNI_FREE(msg);
898
899 set_call_state(c, new_state);
900
901 uni_msg_destroy(m);
902
903 uniapi_call_error(c, UNIAPI_OK, cookie);
904 }
905
906
907 /*
908 * Setup.response from API
909 *
910 * Q.2971:Call-Control-U 13/39 (U6)
911 * Q.2971:Call-Control-U 14/39 (U7)
912 * Q.2971:Call-Control-U 17/39 (U9)
913 * Q.2971:Call-Control-N 39/39 (N1)
914 * Q.2971:Call-Control-N 7/39 (N3)
915 * Q.2971:Call-Control-N 8/39 (N4)
916 */
917 static void
918 unx_setup_response(struct call *c, struct uni_msg *m, uint32_t cookie,
919 enum call_state new_state)
920 {
921 struct uni_all *msg;
922 struct uniapi_setup_response *arg =
923 uni_msg_rptr(m, struct uniapi_setup_response *);
924 struct party *p;
925
926 if ((msg = UNI_ALLOC()) == NULL) {
927 uni_msg_destroy(m);
928 uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
929 return;
930 }
931
932 if (!IE_ISGOOD(c->connid) && IE_ISGOOD(arg->connect.connid))
933 c->connid = arg->connect.connid;
934
935 if (IE_ISGOOD(arg->connect.epref)) {
936 p = uni_find_partyx(c, arg->connect.epref.epref,
937 !arg->connect.epref.flag);
938 if (p == NULL) {
939 uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
940 UNI_FREE(msg);
941 uni_msg_destroy(m);
942 return;
943 }
944 /* we need to remember that we have sent the CONNECT from this
945 * party because the CONNECT ACK must move only this party
946 * into P7 */
947 p->flags |= PARTY_CONNECT;
948
949 } else if (c->type == CALL_LEAF) {
950 /* XXX don't mandate if only one party */
951 uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
952 UNI_FREE(msg);
953 uni_msg_destroy(m);
954 return;
955 }
956
957 /* inform the parties on the network side */
958 if (c->uni->proto == UNIPROTO_UNI40N && c->type == CALL_LEAF)
959 TAILQ_FOREACH(p, &c->parties, link)
960 uni_enq_party(p, SIGP_SETUP_response, 0, NULL, NULL);
961
962 msg->u.connect = arg->connect;
963 MK_MSG_ORIG(msg, UNI_CONNECT, c->cref, !c->mine);
964 (void)uni_send_output(msg, c->uni);
965 UNI_FREE(msg);
966
967 if (c->uni->proto == UNIPROTO_UNI40U)
968 TIMER_START_CALL(c, t313, c->uni->timer313);
969
970 set_call_state(c, new_state);
971
972 uni_msg_destroy(m);
973
974 uniapi_call_error(c, UNIAPI_OK, cookie);
975 }
976
977 /*
978 * Setup_complete.request
979 *
980 * Q.2971:Call-Control-N 15/39 (N8)
981 */
982 static void
983 n8_setup_compl_request(struct call *c, struct uni_msg *m, uint32_t cookie,
984 enum call_state new_state)
985 {
986 struct uni_all *msg;
987 struct uniapi_setup_complete_request *arg =
988 uni_msg_rptr(m, struct uniapi_setup_complete_request *);
989 struct party *p;
990
991 if ((msg = UNI_ALLOC()) == NULL) {
992 uni_msg_destroy(m);
993 uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
994 return;
995 }
996
997 /* inform the parties on the network side */
998 if (c->uni->proto == UNIPROTO_UNI40N &&
999 (c->type == CALL_LEAF || c->type == CALL_ROOT)) {
1000 TAILQ_FOREACH(p, &c->parties, link)
1001 uni_enq_party(p, SIGP_SETUP_COMPL_request,
1002 0, NULL, NULL);
1003 }
1004
1005 msg->u.connect_ack = arg->connect_ack;
1006 MK_MSG_ORIG(msg, UNI_CONNECT_ACK, c->cref, !c->mine);
1007 (void)uni_send_output(msg, c->uni);
1008 UNI_FREE(msg);
1009
1010 set_call_state(c, new_state);
1011
1012 uni_msg_destroy(m);
1013
1014 uniapi_call_error(c, UNIAPI_OK, cookie);
1015 }
1016
1017 /*
1018 * CONNECT message
1019 *
1020 * Q.2971:Call-Control-U 7-8/39 (U3)
1021 * Q.2971:Call-Control-U 11/39 (U4)
1022 * Q.2971:Call-Control-U 37/39 (U1)
1023 * Q.2971:Call-Control-N 9-10/39 (N6)
1024 * Q.2971:Call-Control-N 14/39 (N7)
1025 * Q.2971:Call-Control-N 17/39 (N9)
1026 */
1027 static void
1028 unx_connect(struct call *c, struct uni_msg *m, struct uni_all *u,
1029 enum call_state new_state)
1030 {
1031 struct uni_connect *co = &u->u.connect;
1032 struct uniapi_setup_confirm *conf;
1033 struct uni_msg *api;
1034 struct uni_all *ack;
1035 struct party *p;
1036
1037 conf = ALLOC_API(struct uniapi_setup_confirm, api);
1038 if (conf == NULL) {
1039 ignore:
1040 UNI_FREE(u);
1041 uni_msg_destroy(m);
1042 return;
1043 }
1044 if ((ack = UNI_ALLOC()) == NULL) {
1045 uni_msg_destroy(api);
1046 goto ignore;
1047 }
1048
1049 /*
1050 * Analyze message
1051 */
1052 (void)uni_decode_body(m, u, &c->uni->cx);
1053 if (!IE_ISPRESENT(c->connid) && !IE_ISGOOD(co->connid))
1054 uni_mandate_ie(c->uni, UNI_IE_CONNID);
1055
1056 /*
1057 * Q.2971: L3MU_01_05 requires the epref to be present.
1058 */
1059 p = NULL;
1060 if (c->msg_setup.bearer.cfg == UNI_BEARER_MP) {
1061 if (IE_ISPRESENT(c->msg_setup.epref)) {
1062 if (!IE_ISPRESENT(co->epref))
1063 uni_mandate_ie(c->uni, UNI_IE_EPREF); \
1064
1065 if (IE_ISGOOD(co->epref) &&
1066 co->epref.flag != 1) {
1067 IE_SETERROR(co->epref);
1068 (void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF,
1069 co->epref.h.act, UNI_IERR_BAD);
1070 }
1071 }
1072
1073 if (IE_ISGOOD(co->epref)) {
1074 p = uni_find_party(c, &co->epref);
1075 if (p == NULL) {
1076 respond_drop_party_ack(c, &co->epref,
1077 UNI_CAUSE_ENDP_INV);
1078 uni_msg_destroy(api);
1079 UNI_FREE(ack);
1080 goto ignore;
1081 }
1082 }
1083 }
1084
1085 switch (uni_verify(c->uni, u->u.hdr.act)) {
1086
1087 case VFY_CLR:
1088 uni_vfy_collect_ies(c->uni);
1089 clear_callD(c);
1090 /* FALLTHRU */
1091 case VFY_I:
1092 uni_msg_destroy(api);
1093 UNI_FREE(ack);
1094 goto ignore;
1095
1096 case VFY_RAIM:
1097 case VFY_RAI:
1098 report:
1099 uni_respond_status_verify(c->uni, &u->u.hdr.cref,
1100 map_callstate(c->cstate), NULL, 0);
1101 uni_msg_destroy(api);
1102 UNI_FREE(ack);
1103 goto ignore;
1104
1105 case VFY_RAP:
1106 case VFY_RAPU:
1107 if (c->type == CALL_ROOT && !IE_ISGOOD(co->epref))
1108 goto report;
1109 uni_respond_status_verify(c->uni, &u->u.hdr.cref,
1110 map_callstate(new_state), NULL, 0);
1111 /* FALLTHRU */
1112 case VFY_OK:
1113 break;
1114 }
1115
1116 if (IE_ISGOOD(co->connid))
1117 c->connid = co->connid;
1118
1119 if (c->cstate == CALLST_U1 || c->cstate == CALLST_N6)
1120 TIMER_STOP_CALL(c, t303);
1121 else if (c->cstate == CALLST_U3 || c->cstate == CALLST_N9)
1122 TIMER_STOP_CALL(c, t310);
1123 else if (c->cstate == CALLST_U4 || c->cstate == CALLST_N7) {
1124 if(c->type == CALL_P2P)
1125 TIMER_STOP_CALL(c, t301);
1126 }
1127
1128 /*
1129 * This is sent to the party only on the user side and only
1130 * to the one party in the epref (L3MU_05_03).
1131 */
1132 if (c->uni->proto == UNIPROTO_UNI40U &&
1133 (c->type == CALL_LEAF || c->type == CALL_ROOT))
1134 uni_enq_party(p, SIGP_CONNECT, 0, NULL, NULL);
1135
1136 conf->connect.hdr = u->u.hdr;
1137 copy_msg_connect(co, &conf->connect);
1138 c->uni->funcs->uni_output(c->uni, c->uni->arg,
1139 UNIAPI_SETUP_confirm, 0, api);
1140
1141 if (c->uni->proto == UNIPROTO_UNI40U) {
1142 /* this is left to the application on the network side */
1143 MK_MSG_ORIG(ack, UNI_CONNECT_ACK, c->cref, !c->mine);
1144 (void)uni_send_output(ack, c->uni);
1145 UNI_FREE(ack);
1146 }
1147
1148 UNI_FREE(u);
1149 uni_msg_destroy(m);
1150
1151 set_call_state(c, new_state);
1152 }
1153
1154 /*
1155 * T313 (Connect) timer tick.
1156 *
1157 * Q.2971:Call-Control-U 15/39
1158 */
1159 static void
1160 u8_t313(struct call *c)
1161 {
1162 VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T313 tick",
1163 c->cref, c->mine ? "mine" : "his");
1164
1165 MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_RECOVER);
1166 ADD_CAUSE_TIMER(c->uni->cause, "313");
1167 clear_callD(c);
1168 }
1169
1170 /*
1171 * CONNECT ACKNOWLEDGE message in U8
1172 *
1173 * Q.2971:Call-Control-U 15-16/39
1174 */
1175 static void
1176 u8_connect_ack(struct call *c, struct uni_msg *m, struct uni_all *u,
1177 enum call_state new_state)
1178 {
1179 struct uniapi_setup_complete_indication *ind;
1180 struct uni_msg *api;
1181
1182 ind = ALLOC_API(struct uniapi_setup_complete_indication, api);
1183 if (ind == NULL) {
1184 ignore:
1185 uni_msg_destroy(m);
1186 UNI_FREE(u);
1187 return;
1188 }
1189
1190 /*
1191 * Analyze message
1192 */
1193 (void)uni_decode_body(m, u, &c->uni->cx);
1194
1195 switch (uni_verify(c->uni, u->u.hdr.act)) {
1196
1197 case VFY_CLR:
1198 uni_vfy_collect_ies(c->uni);
1199 clear_callD(c);
1200 /* FALLTHRU */
1201 case VFY_I:
1202 uni_msg_destroy(api);
1203 goto ignore;
1204
1205 case VFY_RAIM:
1206 case VFY_RAI:
1207 uni_respond_status_verify(c->uni, &u->u.hdr.cref,
1208 map_callstate(c->cstate), NULL, 0);
1209 uni_msg_destroy(api);
1210 goto ignore;
1211
1212 case VFY_RAP:
1213 case VFY_RAPU:
1214 uni_respond_status_verify(c->uni, &u->u.hdr.cref,
1215 map_callstate(new_state), NULL, 0);
1216 /* FALLTHRU */
1217 case VFY_OK:
1218 break;
1219 }
1220
1221 TIMER_STOP_CALL(c, t313);
1222
1223 if (c->type == CALL_LEAF) {
1224 struct party *p;
1225
1226 TAILQ_FOREACH(p, &c->parties, link) {
1227 if (p->flags & PARTY_CONNECT) {
1228 uni_enq_party(p, SIGP_CONNECT_ACK,
1229 0, NULL, NULL);
1230 break;
1231 }
1232 }
1233 }
1234
1235 ind->connect_ack.hdr = u->u.hdr;
1236 copy_msg_connect_ack(&u->u.connect_ack, &ind->connect_ack);
1237 c->uni->funcs->uni_output(c->uni, c->uni->arg,
1238 UNIAPI_SETUP_COMPLETE_indication, 0, api);
1239
1240 UNI_FREE(u);
1241 uni_msg_destroy(m);
1242
1243 set_call_state(c, new_state);
1244 }
1245
1246 /*
1247 * CONNECT ACKNOWLEDGE message in N10
1248 *
1249 * Q.2971:Call-Control-N 18/39
1250 */
1251 static void
1252 n10_connect_ack(struct call *c, struct uni_msg *m, struct uni_all *u)
1253 {
1254 /*
1255 * Analyze message
1256 */
1257 (void)uni_decode_body(m, u, &c->uni->cx);
1258
1259 switch (uni_verify(c->uni, u->u.hdr.act)) {
1260
1261 case VFY_CLR:
1262 uni_vfy_collect_ies(c->uni);
1263 clear_callD(c);
1264 /* FALLTHRU */
1265 case VFY_I:
1266 uni_msg_destroy(m);
1267 UNI_FREE(u);
1268 return;
1269
1270 case VFY_RAIM:
1271 case VFY_RAI:
1272 case VFY_RAP:
1273 case VFY_RAPU:
1274 uni_respond_status_verify(c->uni, &u->u.hdr.cref,
1275 map_callstate(c->cstate), NULL, 0);
1276 /* FALLTHRU */
1277 case VFY_OK:
1278 uni_msg_destroy(m);
1279 UNI_FREE(u);
1280 return;
1281 }
1282 }
1283
1284 /*
1285 * Release.response in U6 or U12.
1286 *
1287 * Q.2971:Call-Control-U 12/39 (U6)
1288 * Q.2971:Call-Control-U 30/39 (U12)
1289 * Q.2971:Call-Control-N 6/39 (N1)
1290 * Q.2971:Call-Control-N 29/39 (N11)
1291 */
1292 static void
1293 unx_release_response(struct call *c, struct uni_msg *m, uint32_t cookie)
1294 {
1295 struct party *p;
1296 struct uni_all *msg;
1297 struct uniapi_release_response *arg =
1298 uni_msg_rptr(m, struct uniapi_release_response *);
1299
1300 if ((msg = UNI_ALLOC()) == NULL) {
1301 uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
1302 uni_msg_destroy(m);
1303 return;
1304 }
1305
1306 if (c->cstate == CALLST_U6 || c->cstate == CALLST_N1) {
1307 if (c->type == CALL_ROOT || c->type == CALL_LEAF) {
1308 TAILQ_FOREACH(p, &c->parties, link)
1309 uni_enq_party(p, SIGP_RELEASE_response,
1310 cookie, NULL, NULL);
1311 }
1312 }
1313 msg->u.release_compl = arg->release_compl;
1314 MK_MSG_ORIG(msg, UNI_RELEASE_COMPL, c->cref, !c->mine);
1315 (void)uni_send_output(msg, c->uni);
1316 UNI_FREE(msg);
1317
1318 uni_msg_destroy(m);
1319
1320 uniapi_call_error(c, UNIAPI_OK, cookie);
1321
1322 uni_destroy_call(c, 0);
1323 }
1324
1325 /*
1326 * Got a RELEASE COMPLETE in any state expect U0
1327 *
1328 * Q.2971:Call-Control-U 25/39
1329 * Q.2971:Call-Control-N 26/39
1330 *
1331 * This is also called from the restart processes.
1332 */
1333 void
1334 uni_release_compl(struct call *c, struct uni_all *u)
1335 {
1336 struct uni_msg *api;
1337 struct uniapi_release_confirm *conf;
1338 struct party *p;
1339 u_int i, j;
1340
1341 if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) == NULL)
1342 return;
1343
1344 reset_all_timers(c);
1345 if (c->type == CALL_ROOT || c->type == CALL_LEAF) {
1346 TAILQ_FOREACH(p, &c->parties, link)
1347 uni_enq_party(p, SIGP_RELEASE_COMPL, 0, NULL, NULL);
1348 /* YYY optional call reoffering 10.3.3/10.3.4 */
1349 }
1350 conf->release.hdr = u->u.hdr;
1351
1352 for (i = j = 0; i < 2; i++)
1353 if (IE_ISGOOD(u->u.release_compl.cause[i]))
1354 conf->release.cause[j++] = u->u.release_compl.cause[i];
1355 for (i = j = 0; i < UNI_NUM_IE_GIT; i++)
1356 if (IE_ISGOOD(u->u.release_compl.git[i]))
1357 conf->release.git[j++] = u->u.release_compl.git[i];
1358 if (IE_ISGOOD(u->u.release_compl.uu))
1359 conf->release.uu = u->u.release_compl.uu;
1360 if (IE_ISGOOD(u->u.release_compl.crankback))
1361 conf->release.crankback = u->u.release_compl.crankback;
1362
1363 c->uni->funcs->uni_output(c->uni, c->uni->arg,
1364 UNIAPI_RELEASE_confirm, 0, api);
1365
1366 uni_destroy_call(c, 0);
1367 }
1368 static void
1369 unx_release_compl(struct call *c, struct uni_msg *m, struct uni_all *u)
1370 {
1371
1372 (void)uni_decode_body(m, u, &c->uni->cx);
1373 (void)uni_verify(c->uni, u->u.hdr.act); /* no point :-) */
1374
1375 uni_release_compl(c, u);
1376
1377 uni_msg_destroy(m);
1378 UNI_FREE(u);
1379 }
1380
1381 /*
1382 * Got a RELEASE COMPLETE in any state expect U0 and U11
1383 *
1384 * Q.2971:Call-Control-U 25/39
1385 * Q.2971:Call-Control-N 26/39
1386 */
1387 static void
1388 unx_release(struct call *c, struct uni_msg *m, struct uni_all *u,
1389 enum call_state new_state)
1390 {
1391 struct uniapi_release_indication *ind;
1392 struct uni_msg *api;
1393
1394 if ((ind = ALLOC_API(struct uniapi_release_indication, api)) == NULL) {
1395 uni_msg_destroy(m);
1396 UNI_FREE(u);
1397 return;
1398 }
1399
1400 (void)uni_decode_body(m, u, &c->uni->cx);
1401 (void)uni_verify(c->uni, u->u.hdr.act); /* no point :-) */
1402
1403 reset_all_timers(c);
1404 if (c->type == CALL_ROOT || c->type == CALL_LEAF) {
1405 struct party *p;
1406
1407 TAILQ_FOREACH(p, &c->parties, link)
1408 uni_enq_party(p, SIGP_RELEASE, 0, NULL, NULL);
1409 /* YYY optional call reoffering 10.3.3/10.3.4 */
1410 }
1411 if (c->cstate != new_state) {
1412 /*
1413 * According to Q.2971 we should send a 2nd
1414 * Release.indication.
1415 * According to Q.2931 the recipte of a RELEASE in U12/N11
1416 * is illegal.
1417 * According to us make it legal, but don't send a 2nd
1418 * indication.
1419 */
1420 ind->release.hdr = u->u.hdr;
1421 copy_msg_release(&u->u.release, &ind->release);
1422
1423 c->uni->funcs->uni_output(c->uni, c->uni->arg,
1424 UNIAPI_RELEASE_indication, 0, api);
1425 } else
1426 uni_msg_destroy(api);
1427
1428 uni_msg_destroy(m);
1429 UNI_FREE(u);
1430
1431 set_call_state(c, new_state);
1432 }
1433
1434 /*
1435 * Got RELEASE in U11 or N12
1436 *
1437 * Q.2971:Call-Control-U 28/39
1438 * Q.2971:Call-Control-N 30/39
1439 */
1440 static void
1441 u11n12_release(struct call *c, struct uni_msg *m, struct uni_all *u)
1442 {
1443 struct uniapi_release_confirm *conf;
1444 struct uni_msg *api;
1445
1446 if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) == NULL) {
1447 uni_msg_destroy(m);
1448 UNI_FREE(u);
1449 return;
1450 }
1451
1452 (void)uni_decode_body(m, u, &c->uni->cx);
1453 (void)uni_verify(c->uni, u->u.hdr.act); /* no point :-) */
1454
1455 TIMER_STOP_CALL(c, t308);
1456
1457 conf->release.hdr = u->u.hdr;
1458 copy_msg_release(&u->u.release, &conf->release);
1459
1460 c->uni->funcs->uni_output(c->uni, c->uni->arg,
1461 UNIAPI_RELEASE_confirm, 0, api);
1462
1463 uni_msg_destroy(m);
1464 UNI_FREE(u);
1465
1466 uni_destroy_call(c, 0);
1467 }
1468
1469 /*
1470 * NOTIFY message
1471 *
1472 * Q.2971:Call-Control-U 18/39
1473 * Q.2971:Call-Control-N 19/39
1474 */
1475 static void
1476 unx_notify(struct call *c, struct uni_msg *m, struct uni_all *u)
1477 {
1478 struct uniapi_notify_indication *ind;
1479 struct uni_msg *api;
1480 struct party *p = NULL;
1481
1482 if ((ind = ALLOC_API(struct uniapi_notify_indication, api)) == NULL) {
1483 ignore:
1484 uni_msg_destroy(m);
1485 UNI_FREE(u);
1486 return;
1487 }
1488
1489 /*
1490 * Analyze message
1491 */
1492 (void)uni_decode_body(m, u, &c->uni->cx);
1493 MANDATE_IE(c->uni, u->u.notify.notify, UNI_IE_NOTIFY);
1494
1495 if (IE_ISGOOD(u->u.notify.epref)) {
1496 if ((p = uni_find_party(c, &u->u.notify.epref)) == NULL) {
1497 respond_drop_party_ack(c, &u->u.notify.epref,
1498 UNI_CAUSE_ENDP_INV);
1499 uni_msg_destroy(api);
1500 goto ignore;
1501 }
1502 }
1503
1504 switch (uni_verify(c->uni, u->u.hdr.act)) {
1505
1506 case VFY_CLR:
1507 uni_msg_destroy(api);
1508 uni_vfy_collect_ies(c->uni);
1509 clear_callD(c);
1510 goto ignore;
1511
1512 case VFY_RAIM:
1513 case VFY_RAI:
1514 uni_respond_status_verify(c->uni, &u->u.hdr.cref,
1515 map_callstate(c->cstate), &u->u.notify.epref,
1516 p ? p->state : 0);
1517 /* FALLTHRU */
1518 case VFY_I:
1519 uni_msg_destroy(api);
1520 goto ignore;
1521
1522 case VFY_RAP:
1523 case VFY_RAPU:
1524 uni_respond_status_verify(c->uni, &u->u.hdr.cref,
1525 map_callstate(c->cstate), &u->u.notify.epref,
1526 p ? p->state : 0);
1527 case VFY_OK:
1528 /* FALLTHRU */
1529 break;
1530 }
1531
1532 ind->notify.hdr = u->u.hdr;
1533 copy_msg_notify(&u->u.notify, &ind->notify);
1534 c->uni->funcs->uni_output(c->uni, c->uni->arg,
1535 UNIAPI_NOTIFY_indication, 0, api);
1536
1537 UNI_FREE(u);
1538 uni_msg_destroy(m);
1539 }
1540
1541 /*
1542 * Notify.request from user
1543 *
1544 * Q.2971:Call-Control-U 18/39
1545 * Q.2971:Call-Control-N 19/39
1546 */
1547 static void
1548 unx_notify_request(struct call *c, struct uni_msg *m, uint32_t cookie)
1549 {
1550 struct uni_all *msg;
1551 struct uniapi_notify_request *arg =
1552 uni_msg_rptr(m, struct uniapi_notify_request *);
1553
1554 if ((msg = UNI_ALLOC()) == NULL) {
1555 uni_msg_destroy(m);
1556 uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
1557 return;
1558 }
1559
1560 msg->u.notify = arg->notify;
1561 MK_MSG_ORIG(msg, UNI_NOTIFY, c->cref, !c->mine);
1562 (void)uni_send_output(msg, c->uni);
1563 UNI_FREE(msg);
1564
1565 uni_msg_destroy(m);
1566
1567 uniapi_call_error(c, UNIAPI_OK, cookie);
1568 }
1569
1570 /**********************************************************************/
1571
1572 /*
1573 * Release.request from API in any state except U11, U12, N11, N12
1574 *
1575 * Q.2971:Call-Control-U 27/39
1576 * Q.2971:Call-Control-N 28/39
1577 */
1578 static void
1579 unx_release_request(struct call *c, struct uni_msg *m, uint32_t cookie,
1580 enum call_state new_state)
1581 {
1582 struct uni_all *msg;
1583 struct uniapi_release_request *arg =
1584 uni_msg_rptr(m, struct uniapi_release_request *);
1585 struct party *p;
1586
1587 if ((msg = UNI_ALLOC()) == NULL) {
1588 uni_msg_destroy(m);
1589 uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
1590 return;
1591 }
1592
1593 reset_all_timers(c);
1594
1595 if (c->type == CALL_LEAF || c->type == CALL_ROOT) {
1596 TAILQ_FOREACH(p, &c->parties, link) {
1597 uni_enq_party(p, SIGP_RELEASE_request, cookie,
1598 NULL, NULL);
1599 }
1600 }
1601
1602 c->msg_release = arg->release;
1603 if (!IE_ISPRESENT(c->msg_release.cause[0]) &&
1604 !IE_ISPRESENT(c->msg_release.cause[1]))
1605 MK_IE_CAUSE(c->msg_release.cause[0], UNI_CAUSE_LOC_USER,
1606 UNI_CAUSE_UNSPEC);
1607
1608 msg->u.release = c->msg_release;
1609 MK_MSG_ORIG(msg, UNI_RELEASE, c->cref, !c->mine);
1610 (void)uni_send_output(msg, c->uni);
1611 UNI_FREE(msg);
1612
1613 TIMER_START_CALL(c, t308, c->uni->timer308);
1614 c->cnt308 = 0;
1615
1616 set_call_state(c, new_state);
1617
1618 uni_msg_destroy(m);
1619
1620 uniapi_call_error(c, UNIAPI_OK, cookie);
1621 }
1622
1623 /*
1624 * Message with unknown EPREF - send a drop party according to 9.5.3.2.3a)
1625 */
1626 static void
1627 respond_drop_party_ack(struct call *c, struct uni_ie_epref *epref,
1628 u_int cause)
1629 {
1630 struct uni_all *msg;
1631
1632 if ((msg = UNI_ALLOC()) == NULL)
1633 return;
1634
1635 MK_MSG_ORIG(msg, UNI_DROP_PARTY_ACK, c->cref, !c->mine);
1636 MK_IE_EPREF(msg->u.drop_party_ack.epref, epref->epref, !epref->flag);
1637 MK_IE_CAUSE(msg->u.drop_party_ack.cause, UNI_CAUSE_LOC_USER, cause);
1638 (void)uni_send_output(msg, c->uni);
1639 UNI_FREE(msg);
1640 }
1641
1642 /*
1643 * T308 (RELEASE) timer
1644 *
1645 * Q.2971:Call-Control-U 28/39
1646 * Q.2971:Call-Control-N 30/39
1647 */
1648 static void
1649 u11n12_t308(struct call *c)
1650 {
1651 struct uni_all *msg;
1652 struct uni_msg *api;
1653 struct uniapi_release_confirm *conf;
1654
1655 VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T308 tick %d",
1656 c->cref, c->mine ? "mine" : "his", c->cnt308 + 1);
1657
1658 if (++c->cnt308 < c->uni->init308) {
1659 if ((msg = UNI_ALLOC()) != NULL) {
1660 msg->u.release = c->msg_release;
1661 MK_MSG_ORIG(msg, UNI_RELEASE, c->cref, !c->mine);
1662 if (!IE_ISPRESENT(msg->u.release.cause[1])) {
1663 MK_IE_CAUSE(msg->u.release.cause[1],
1664 UNI_CAUSE_LOC_USER, UNI_CAUSE_RECOVER);
1665 ADD_CAUSE_TIMER(msg->u.release.cause[1], "308");
1666 }
1667 (void)uni_send_output(msg, c->uni);
1668 UNI_FREE(msg);
1669 }
1670 TIMER_START_CALL(c, t308, c->uni->timer308);
1671 return;
1672 }
1673
1674 /*
1675 * Send indication to API
1676 */
1677 if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) != NULL) {
1678 conf->release.hdr.cref.cref = c->cref;
1679 conf->release.hdr.cref.flag = c->mine;
1680 conf->release.hdr.act = UNI_MSGACT_DEFAULT;
1681 MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER,
1682 UNI_CAUSE_RECOVER);
1683 ADD_CAUSE_TIMER(conf->release.cause[0], "308");
1684
1685 c->uni->funcs->uni_output(c->uni, c->uni->arg,
1686 UNIAPI_RELEASE_confirm, 0, api);
1687 }
1688
1689 uni_destroy_call(c, 0);
1690 }
1691 /**********************************************************************/
1692
1693 /*
1694 * STATUS in U11/U12
1695 *
1696 * Q.2971:Call-Control-U 29/39 (U11)
1697 * Q.2971:Call-Control-U 30/39 (U12)
1698 * Q.2971:Call-Control-N 29/39 (N11)
1699 * Q.2971:Call-Control-N 31/39 (N12)
1700 */
1701 static void
1702 un11un12_status(struct call *c, struct uni_msg *m, struct uni_all *u)
1703 {
1704 enum call_state ns;
1705 struct uniapi_release_confirm *conf;
1706 struct uni_msg *api;
1707 struct party *p;
1708 struct uniapi_status_indication *stat;
1709
1710 /*
1711 * Analyze message
1712 */
1713 (void)uni_decode_body(m, u, &c->uni->cx);
1714 MANDATE_IE(c->uni, u->u.status.callstate, UNI_IE_CALLSTATE);
1715 MANDATE_IE(c->uni, u->u.status.cause, UNI_IE_CAUSE);
1716
1717 ns = c->cstate;
1718 if (IE_ISGOOD(u->u.status.callstate) &&
1719 u->u.status.callstate.state == UNI_CALLSTATE_U0)
1720 ns = CALLST_NULL;
1721
1722 p = NULL;
1723 if (IE_ISGOOD(u->u.status.epref))
1724 p = uni_find_party(c, &u->u.status.epref);
1725
1726 switch (uni_verify(c->uni, u->u.hdr.act)) {
1727
1728 case VFY_CLR:
1729 uni_vfy_collect_ies(c->uni);
1730 clear_callD(c);
1731 uni_msg_destroy(m);
1732 UNI_FREE(u);
1733 return;
1734
1735 case VFY_RAIM:
1736 case VFY_RAI:
1737 case VFY_RAP:
1738 case VFY_RAPU:
1739 uni_respond_status_verify(c->uni, &u->u.hdr.cref,
1740 map_callstate(ns), &u->u.status.epref,
1741 p ? p->state : UNI_EPSTATE_NULL);
1742 case VFY_I:
1743 case VFY_OK:
1744 break;
1745 }
1746
1747 if (ns == c->cstate) {
1748 /*
1749 * Inform API
1750 */
1751 stat = ALLOC_API(struct uniapi_status_indication, api);
1752 if (stat != NULL) {
1753 stat->cref = u->u.hdr.cref;
1754 stat->my_state = map_callstate(c->cstate);
1755 stat->his_state = u->u.status.callstate;
1756 stat->his_cause = u->u.status.cause;
1757 stat->epref = u->u.status.epref;
1758 stat->epstate = u->u.status.epstate;
1759 stat->my_cause = 0;
1760 c->uni->funcs->uni_output(c->uni, c->uni->arg,
1761 UNIAPI_STATUS_indication, 0, api);
1762 }
1763
1764 uni_msg_destroy(m);
1765 UNI_FREE(u);
1766
1767 return;
1768 }
1769
1770 uni_msg_destroy(m);
1771 UNI_FREE(u);
1772
1773 /*
1774 * Send indication to API
1775 */
1776 if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) != NULL) {
1777 conf->release.hdr.cref.cref = c->cref;
1778 conf->release.hdr.cref.flag = c->mine;
1779 conf->release.hdr.act = UNI_MSGACT_DEFAULT;
1780 MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER,
1781 UNI_CAUSE_MSG_INCOMP);
1782 ADD_CAUSE_MTYPE(conf->release.cause[0], UNI_STATUS);
1783
1784 c->uni->funcs->uni_output(c->uni, c->uni->arg,
1785 UNIAPI_RELEASE_confirm, 0, api);
1786 }
1787
1788 uni_destroy_call(c, 0);
1789 }
1790
1791 static int
1792 status_enq_filter(struct sig *sig, void *arg)
1793 {
1794 return (sig->type == SIG_CALL &&
1795 (struct call *)arg == sig->call &&
1796 sig->sig == SIGC_SEND_STATUS_ENQ);
1797 }
1798
1799 /*
1800 * STATUS in any state except U0/U11/U12 N0/N11/N12
1801 *
1802 * Q.2971:Call-Control-U 32/39
1803 * Q.2971:Call-Control-N 33/39
1804 */
1805 static void
1806 unx_status(struct call *c, struct uni_msg *m, struct uni_all *u)
1807 {
1808 struct uniapi_status_indication *stat;
1809 struct uniapi_release_confirm *conf;
1810 enum call_state ns;
1811 struct uni_msg *api;
1812 struct party *p;
1813
1814 /*
1815 * Analyze message
1816 */
1817 (void)uni_decode_body(m, u, &c->uni->cx);
1818 MANDATE_IE(c->uni, u->u.status.callstate, UNI_IE_CALLSTATE);
1819 MANDATE_IE(c->uni, u->u.status.cause, UNI_IE_CAUSE);
1820
1821 ns = c->cstate;
1822 if (IE_ISGOOD(u->u.status.callstate))
1823 ns = state_compat(c, u->u.status.callstate.state);
1824
1825 p = NULL;
1826 if (IE_ISGOOD(u->u.status.epref)) {
1827 p = uni_find_party(c, &u->u.status.epref);
1828 MANDATE_IE(c->uni, u->u.status.epstate, UNI_IE_EPSTATE);
1829 }
1830
1831 switch (uni_verify(c->uni, u->u.hdr.act)) {
1832
1833 case VFY_CLR:
1834 uni_vfy_collect_ies(c->uni);
1835 clear_callD(c);
1836 uni_msg_destroy(m);
1837 UNI_FREE(u);
1838 return;
1839
1840 case VFY_RAIM:
1841 case VFY_RAI:
1842 case VFY_RAP:
1843 case VFY_RAPU:
1844 uni_respond_status_verify(c->uni, &u->u.hdr.cref,
1845 map_callstate(ns), &u->u.notify.epref,
1846 p ? p->state : UNI_EPSTATE_NULL);
1847 /* FALLTHRU */
1848 case VFY_I:
1849 case VFY_OK:
1850 break;
1851 }
1852
1853 if (u->u.status.callstate.state == UNI_CALLSTATE_U0) {
1854 /* release_complete */
1855 uni_msg_destroy(m);
1856 UNI_FREE(u);
1857
1858 if (c->type == CALL_LEAF || c->type == CALL_ROOT) {
1859 TAILQ_FOREACH(p, &c->parties, link)
1860 uni_enq_party(p, SIGP_RELEASE_COMPL,
1861 0, NULL, NULL);
1862 }
1863 /*
1864 * Send indication to API
1865 */
1866 conf = ALLOC_API(struct uniapi_release_confirm, api);
1867 if (conf != NULL) {
1868 conf->release.hdr.cref.cref = c->cref;
1869 conf->release.hdr.cref.flag = c->mine;
1870 conf->release.hdr.act = UNI_MSGACT_DEFAULT;
1871 MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER,
1872 UNI_CAUSE_MSG_INCOMP);
1873 ADD_CAUSE_MTYPE(conf->release.cause[0], UNI_STATUS);
1874
1875 c->uni->funcs->uni_output(c->uni, c->uni->arg,
1876 UNIAPI_RELEASE_confirm, 0, api);
1877 }
1878 uni_destroy_call(c, 0);
1879 return;
1880 }
1881
1882 if (IE_ISGOOD(u->u.status.cause) &&
1883 u->u.status.cause.cause == UNI_CAUSE_STATUS) {
1884 c->se_active = 0;
1885 TIMER_STOP_CALL(c, t322);
1886 uni_undel(c->uni, status_enq_filter, c);
1887 }
1888
1889 /*
1890 * Inform API
1891 */
1892 if ((stat = ALLOC_API(struct uniapi_status_indication, api)) != NULL) {
1893 stat->cref = u->u.hdr.cref;
1894 stat->my_state = map_callstate(c->cstate);
1895 stat->his_state = u->u.status.callstate;
1896 stat->his_cause = u->u.status.cause;
1897 stat->epref = u->u.status.epref;
1898 stat->epstate = u->u.status.epstate;
1899 }
1900
1901 if (ns == c->cstate) {
1902 /* compatible or recovered */
1903 if (p != NULL)
1904 uni_enq_party(p, SIGP_STATUS, 0, m, u);
1905 else {
1906 if (IE_ISGOOD(u->u.status.epref) &&
1907 (!IE_ISGOOD(u->u.status.epstate) ||
1908 u->u.status.epstate.state != UNI_EPSTATE_NULL))
1909 respond_drop_party_ack(c, &u->u.status.epref,
1910 UNI_CAUSE_MSG_INCOMP);
1911
1912 uni_msg_destroy(m);
1913 UNI_FREE(u);
1914 }
1915 if (stat != NULL) {
1916 stat->my_cause = 0;
1917 c->uni->funcs->uni_output(c->uni, c->uni->arg,
1918 UNIAPI_STATUS_indication, 0, api);
1919 }
1920
1921 return;
1922 }
1923
1924 /* incompatible */
1925 if (stat != NULL) {
1926 stat->my_cause = UNI_CAUSE_MSG_INCOMP;
1927 c->uni->funcs->uni_output(c->uni, c->uni->arg,
1928 UNIAPI_STATUS_indication, 0, api);
1929 }
1930
1931 MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_MSG_INCOMP);
1932
1933 uni_msg_destroy(m);
1934 UNI_FREE(u);
1935
1936 clear_callD(c);
1937 }
1938
1939 /*
1940 * Enquiry peer status
1941 *
1942 * Q.2971:Call-Control-U 31/39
1943 * Q.2971:Call-Control-N 32/39
1944 */
1945 static void
1946 unx_status_enquiry_request(struct call *c, struct uni_msg *msg, uint32_t cookie)
1947 {
1948 struct uniapi_status_enquiry_request *arg =
1949 uni_msg_rptr(msg, struct uniapi_status_enquiry_request *);
1950 struct party *p;
1951 struct uni_all *stat;
1952
1953 if (c->se_active) {
1954 /* This case is not handled in the SDLs */
1955 uniapi_call_error(c, UNIAPI_ERROR_BUSY, cookie);
1956 uni_msg_destroy(msg);
1957 return;
1958 }
1959 if ((c->type == CALL_ROOT || c->type == CALL_LEAF) &&
1960 IE_ISGOOD(arg->epref)) {
1961 if ((p = uni_find_partyx(c, arg->epref.epref, !arg->epref.flag))
1962 == NULL) {
1963 uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
1964 uni_msg_destroy(msg);
1965 return;
1966 }
1967 uni_msg_destroy(msg);
1968 uni_enq_party(p, SIGP_STATUS_ENQUIRY_request, cookie,
1969 NULL, NULL);
1970 return;
1971 }
1972 if ((stat = UNI_ALLOC()) == NULL) {
1973 uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
1974 uni_msg_destroy(msg);
1975 return;
1976 }
1977 memset(&c->stat_epref, 0, sizeof(c->stat_epref));
1978 MK_MSG_ORIG(stat, UNI_STATUS_ENQ, c->cref, !c->mine);
1979 (void)uni_send_output(stat, c->uni);
1980 UNI_FREE(stat);
1981
1982 TIMER_START_CALL(c, t322, c->uni->timer322);
1983 c->cnt322 = 0;
1984 c->se_active = 1;
1985
1986 uniapi_call_error(c, UNIAPI_OK, cookie);
1987 }
1988
1989 /*
1990 * T322 tick
1991 *
1992 * Q.2971:Call-Control-U 34/39
1993 * Q.2971:Call-Control-N 35/39
1994 */
1995 static void
1996 unx_t322(struct call *c)
1997 {
1998 struct uni_all *stat;
1999
2000 VERBOSE(c->uni, UNI_FAC_TIMEOUT, 1, "call %u/%s T322 tick %d",
2001 c->cref, c->mine ? "mine" : "his", c->cnt322 + 1);
2002
2003 if (++c->cnt322 < c->uni->init322) {
2004 if ((stat = UNI_ALLOC()) != NULL) {
2005 MK_MSG_ORIG(stat, UNI_STATUS_ENQ, c->cref, !c->mine);
2006 stat->u.status_enq.epref = c->stat_epref;
2007 (void)uni_send_output(stat, c->uni);
2008 UNI_FREE(stat);
2009 }
2010 TIMER_START_CALL(c, t322, c->uni->timer322);
2011 return;
2012 }
2013 c->se_active = 0;
2014
2015 MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_RECOVER);
2016 ADD_CAUSE_TIMER(c->uni->cause, "322");
2017
2018 clear_callD(c);
2019 }
2020
2021 /*
2022 * STATUS ENQUIRY message
2023 *
2024 * Q.2971:Call-Control-U 31/39
2025 * Q.2971:Call-Control-N 32/39
2026 */
2027 static void
2028 unx_status_enq(struct call *c, struct uni_msg *m, struct uni_all *u)
2029 {
2030 struct party *p = NULL;
2031 u_int epref, flag;
2032
2033 /*
2034 * Analyze message
2035 */
2036 (void)uni_decode_body(m, u, &c->uni->cx);
2037
2038 switch (uni_verify(c->uni, u->u.hdr.act)) {
2039
2040 case VFY_CLR:
2041 uni_vfy_collect_ies(c->uni);
2042 clear_callD(c);
2043 uni_msg_destroy(m);
2044 UNI_FREE(u);
2045 return;
2046
2047 case VFY_RAIM:
2048 case VFY_RAI:
2049 case VFY_RAP:
2050 case VFY_RAPU:
2051 case VFY_I:
2052 case VFY_OK:
2053 break;
2054 }
2055
2056 uni_msg_destroy(m);
2057
2058 if ((c->type == CALL_ROOT || c->type == CALL_LEAF) &&
2059 IE_ISGOOD(u->u.status_enq.epref)) {
2060 p = uni_find_party(c, &u->u.status_enq.epref);
2061
2062 epref = u->u.status_enq.epref.epref;
2063 flag = u->u.status_enq.epref.flag;
2064 memset(u, 0, sizeof(*u));
2065 MK_IE_EPREF(u->u.status.epref, epref, !flag);
2066
2067 if (p != NULL)
2068 MK_IE_EPSTATE(u->u.status.epstate, p->state);
2069 else
2070 MK_IE_EPSTATE(u->u.status.epstate, UNI_EPSTATE_NULL);
2071 } else
2072 memset(u, 0, sizeof(*u));
2073
2074
2075 MK_MSG_ORIG(u, UNI_STATUS, c->cref, !c->mine);
2076 MK_IE_CALLSTATE(u->u.status.callstate, map_callstate(c->cstate));
2077 MK_IE_CAUSE(u->u.status.cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_STATUS);
2078 (void)uni_send_output(u, c->uni);
2079 UNI_FREE(u);
2080 }
2081
2082 /**********************************************************************/
2083
2084 /*
2085 * Link-release.indication from SAAL in state U10 or N10.
2086 *
2087 * Q.2971:Call-Control-U 19/39
2088 * Q.2971:Call-Control-N 20/39
2089 */
2090 static void
2091 un10_link_release_indication(struct call *c)
2092 {
2093 struct party *p;
2094
2095 if (c->type == CALL_LEAF || c->type == CALL_ROOT)
2096 TAILQ_FOREACH(p, &c->parties, link) {
2097 if (p->state != UNI_EPSTATE_ACTIVE)
2098 uni_enq_party(p, SIGP_RELEASE_COMPL,
2099 0, NULL, NULL);
2100 }
2101
2102 uni_enq_coord(c->uni, SIGO_LINK_ESTABLISH_request, 0, NULL);
2103 }
2104
2105 /*
2106 * Link-release.indication from SAAL in all state except U10 and N10.
2107 *
2108 * Q.2971:Call-Control-U 36/39
2109 * Q.2971:Call-Control-N 37/39
2110 */
2111 static void
2112 unx_link_release_indication(struct call *c)
2113 {
2114 struct uniapi_release_confirm *conf;
2115 struct uni_msg *api;
2116 struct party *p;
2117
2118 if (c->type == CALL_LEAF || c->type == CALL_ROOT)
2119 TAILQ_FOREACH(p, &c->parties, link)
2120 uni_enq_party(p, SIGP_RELEASE_COMPL, 0, NULL, NULL);
2121
2122 if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) != NULL) {
2123 conf->release.hdr.cref.cref = c->cref;
2124 conf->release.hdr.cref.flag = c->mine;
2125 conf->release.hdr.act = UNI_MSGACT_DEFAULT;
2126 MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER,
2127 UNI_CAUSE_DST_OOO);
2128
2129 c->uni->funcs->uni_output(c->uni, c->uni->arg,
2130 UNIAPI_RELEASE_confirm, 0, api);
2131 }
2132
2133 uni_destroy_call(c, 0);
2134 }
2135
2136 /*
2137 * Failed to establish SAAL link. Can happen only in U10 or N10.
2138 *
2139 * Q.2971:Call-Control-U 19/39
2140 * Q.2971:Call-Control-N 20/39
2141 */
2142 static void
2143 un10_link_establish_error_indication(struct call *c)
2144 {
2145 struct party *p;
2146 struct uni_msg *api;
2147 struct uniapi_release_confirm *conf;
2148
2149 if (c->type == CALL_LEAF || c->type == CALL_ROOT)
2150 TAILQ_FOREACH(p, &c->parties, link)
2151 uni_enq_party(p, SIGP_RELEASE_COMPL, 0, NULL, NULL);
2152
2153 if ((conf = ALLOC_API(struct uniapi_release_confirm, api)) != NULL) {
2154 conf->release.hdr.cref.cref = c->cref;
2155 conf->release.hdr.cref.flag = c->mine;
2156 conf->release.hdr.act = UNI_MSGACT_DEFAULT;
2157 MK_IE_CAUSE(conf->release.cause[0], UNI_CAUSE_LOC_USER,
2158 UNI_CAUSE_DST_OOO);
2159
2160 c->uni->funcs->uni_output(c->uni, c->uni->arg,
2161 UNIAPI_RELEASE_confirm, 0, api);
2162 }
2163
2164 uni_destroy_call(c, 0);
2165 }
2166
2167 /*
2168 * Issue a STATUS ENQUIRY of we are not busy
2169 *
2170 * Q.2971: Call-Control-U: 34/39
2171 * Q.2971: Call-Control-N: 34/39
2172 */
2173 static void
2174 call_se(struct call *c)
2175 {
2176 struct uni_all *stat;
2177
2178 c->cnt322 = 0;
2179 if (c->se_active)
2180 return;
2181
2182 memset(&c->stat_epref, 0, sizeof(c->stat_epref));
2183 if ((stat = UNI_ALLOC()) != NULL) {
2184 MK_MSG_ORIG(stat, UNI_STATUS_ENQ, c->cref, !c->mine);
2185 (void)uni_send_output(stat, c->uni);
2186 UNI_FREE(stat);
2187 }
2188
2189 TIMER_START_CALL(c, t322, c->uni->timer322);
2190 c->se_active = 1;
2191 }
2192
2193 /*
2194 * Link-establish.indication in U10
2195 *
2196 * Q.2971:Call-Control-U 19-20/39
2197 * Q.2971:Call-Control-N 20-22/39
2198 */
2199 static void
2200 un10_link_establish_indication(struct call *c)
2201 {
2202 int act = 0;
2203 struct party *p;
2204
2205 if (c->type == CALL_ROOT || c->type == CALL_LEAF) {
2206 TAILQ_FOREACH(p, &c->parties, link)
2207 if (p->state == UNI_EPSTATE_ACTIVE) {
2208 act = 1;
2209 uni_enq_party(p, SIGP_STATUS_ENQUIRY_request,
2210 0, NULL, NULL);
2211 }
2212 if (act)
2213 return;
2214 }
2215 call_se(c);
2216 }
2217
2218 /*
2219 * Link-establish.indication in NOT U10/U11/U12 N10/N11/N12
2220 *
2221 * Q.2971:Call-Control-U 36/39
2222 * Q.2971:Call-Control-N 37/39
2223 */
2224 static void
2225 unx_link_establish_indication(struct call *c)
2226 {
2227 call_se(c);
2228 }
2229
2230 /*
2231 * Link-establish.confirm in U10 or N10
2232 *
2233 * Q.2971:Call-Control-U 19/39
2234 * Q.2971:Call-Control-N 20/39
2235 */
2236 static void
2237 un10_link_establish_confirm(struct call *c)
2238 {
2239 struct party *p;
2240
2241 if (c->type == CALL_ROOT || c->type == CALL_LEAF) {
2242 TAILQ_FOREACH(p, &c->parties, link)
2243 uni_enq_party(p, SIGP_STATUS_ENQUIRY_request,
2244 0, NULL, NULL);
2245 return;
2246 }
2247
2248 call_se(c);
2249 }
2250
2251 /*
2252 * STATUS ENQ from party
2253 *
2254 * Q.2971:Call-Control-U 21/39
2255 * Q.2971:Call-Control-U 25/39
2256 */
2257 static void
2258 unx_send_party_status_enq(struct call *c, struct uni_all *u)
2259 {
2260 if (c->se_active) {
2261 uni_delenq_sig(c->uni, SIG_CALL, c, NULL,
2262 SIGC_SEND_STATUS_ENQ, 0, NULL, u);
2263 return;
2264 }
2265
2266 c->stat_epref = u->u.status_enq.epref;
2267 (void)uni_send_output(u, c->uni);
2268 UNI_FREE(u);
2269
2270 TIMER_START_CALL(c, t322, c->uni->timer322);
2271 c->se_active = 1;
2272 }
2273
2274 /**********************************************************************/
2275
2276 static void
2277 make_drop_cause(struct call *c, struct uni_ie_cause *cause)
2278 {
2279
2280 if (!IE_ISGOOD(*cause)) {
2281 /* 9.5.7.1 paragraph 2 */
2282 if (IE_ISPRESENT(*cause))
2283 MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER,
2284 UNI_CAUSE_IE_INV);
2285 else
2286 MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER,
2287 UNI_CAUSE_MANDAT);
2288 c->uni->cause.u.ie.len = 1;
2289 c->uni->cause.u.ie.ie[0] = UNI_IE_CAUSE;
2290 c->uni->cause.h.present |= UNI_CAUSE_IE_P;
2291
2292 } else if (!IE_ISGOOD(c->uni->cause))
2293 c->uni->cause = *cause;
2294 }
2295
2296 /*
2297 * Drop-party.indication from Party-Control in any state.
2298 *
2299 * Q.2971:Call-Control-U 23/39
2300 */
2301 static void
2302 ux_drop_party_indication(struct call *c, struct uni_msg *api)
2303 {
2304 struct uniapi_drop_party_indication *drop =
2305 uni_msg_rptr(api, struct uniapi_drop_party_indication *);
2306
2307 if (uni_party_act_count(c, 2) == 0) {
2308 if (c->cstate != CALLST_U11) {
2309 make_drop_cause(c, &drop->drop.cause);
2310 clear_callD(c);
2311 }
2312 uni_msg_destroy(api);
2313 return;
2314 }
2315 c->uni->funcs->uni_output(c->uni, c->uni->arg,
2316 UNIAPI_DROP_PARTY_indication, 0, api);
2317 }
2318
2319 /*
2320 * Drop-party.indication from Party-Control in any state.
2321 *
2322 * Q.2971:Call-Control-N 23/39
2323 */
2324 static void
2325 nx_drop_party_indication(struct call *c, struct uni_msg *api)
2326 {
2327 struct uniapi_drop_party_indication *drop =
2328 uni_msg_rptr(api, struct uniapi_drop_party_indication *);
2329
2330 if (uni_party_act_count(c, 0) == 0) {
2331 if (uni_party_act_count(c, 1) == 0) {
2332 if (c->cstate != CALLST_U11) {
2333 make_drop_cause(c, &drop->drop.cause);
2334 clear_callD(c);
2335 }
2336 uni_msg_destroy(api);
2337 } else {
2338 c->uni->funcs->uni_output(c->uni, c->uni->arg,
2339 UNIAPI_DROP_PARTY_indication, 0, api);
2340 set_call_state(c, CALLST_N7);
2341 }
2342 } else {
2343 c->uni->funcs->uni_output(c->uni, c->uni->arg,
2344 UNIAPI_DROP_PARTY_indication, 0, api);
2345 }
2346 }
2347
2348 /*
2349 * Drop-party-ack.indication from Party-Control in any state.
2350 *
2351 * Q.2971:Call-Control-U 23/39
2352 */
2353 static void
2354 ux_drop_party_ack_indication(struct call *c, struct uni_msg *api)
2355 {
2356 struct uniapi_drop_party_ack_indication *drop =
2357 uni_msg_rptr(api, struct uniapi_drop_party_ack_indication *);
2358
2359 if (uni_party_act_count(c, 2) == 0) {
2360 if (c->cstate != CALLST_U11) {
2361 make_drop_cause(c, &drop->drop.cause);
2362 clear_callD(c);
2363 }
2364 uni_msg_destroy(api);
2365 return;
2366 }
2367 c->uni->funcs->uni_output(c->uni, c->uni->arg,
2368 UNIAPI_DROP_PARTY_ACK_indication, 0, api);
2369 }
2370
2371 /*
2372 * Drop-party-ack.indication from Party-Control in any state.
2373 *
2374 * Q.2971:Call-Control-N 23/39
2375 */
2376 static void
2377 nx_drop_party_ack_indication(struct call *c, struct uni_msg *api)
2378 {
2379 struct uniapi_drop_party_ack_indication *drop =
2380 uni_msg_rptr(api, struct uniapi_drop_party_ack_indication *);
2381
2382 if (uni_party_act_count(c, 0) == 0) {
2383 if (uni_party_act_count(c, 1) == 0) {
2384 if (c->cstate != CALLST_U11) {
2385 make_drop_cause(c, &drop->drop.cause);
2386 clear_callD(c);
2387 }
2388 uni_msg_destroy(api);
2389 } else {
2390 c->uni->funcs->uni_output(c->uni, c->uni->arg,
2391 UNIAPI_DROP_PARTY_ACK_indication, 0, api);
2392 set_call_state(c, CALLST_N7);
2393 }
2394 } else {
2395 c->uni->funcs->uni_output(c->uni, c->uni->arg,
2396 UNIAPI_DROP_PARTY_ACK_indication, 0, api);
2397 }
2398 }
2399
2400 /*
2401 * Add-party-rej.indication from Party-Control in any state.
2402 *
2403 * Q.2971:Call-Control-U 23/39
2404 */
2405 static void
2406 ux_add_party_rej_indication(struct call *c, struct uni_msg *api)
2407 {
2408 struct uniapi_add_party_rej_indication *rej =
2409 uni_msg_rptr(api, struct uniapi_add_party_rej_indication *);
2410
2411 if (uni_party_act_count(c, 2) == 0) {
2412 if (c->cstate != CALLST_U11) {
2413 make_drop_cause(c, &rej->rej.cause);
2414 clear_callD(c);
2415 }
2416 uni_msg_destroy(api);
2417 return;
2418 }
2419 c->uni->funcs->uni_output(c->uni, c->uni->arg,
2420 UNIAPI_ADD_PARTY_REJ_indication, 0, api);
2421 }
2422
2423 /*
2424 * Add-party-rej.indication from Party-Control in any state.
2425 *
2426 * Q.2971:Call-Control-N 23/39
2427 */
2428 static void
2429 nx_add_party_rej_indication(struct call *c, struct uni_msg *api)
2430 {
2431 struct uniapi_add_party_rej_indication *rej =
2432 uni_msg_rptr(api, struct uniapi_add_party_rej_indication *);
2433
2434 if (uni_party_act_count(c, 0) == 0) {
2435 if (uni_party_act_count(c, 1) == 0) {
2436 if (c->cstate != CALLST_U11) {
2437 make_drop_cause(c, &rej->rej.cause);
2438 clear_callD(c);
2439 }
2440 uni_msg_destroy(api);
2441 } else {
2442 c->uni->funcs->uni_output(c->uni, c->uni->arg,
2443 UNIAPI_ADD_PARTY_REJ_indication, 0, api);
2444 set_call_state(c, CALLST_N7);
2445 }
2446 } else {
2447 c->uni->funcs->uni_output(c->uni, c->uni->arg,
2448 UNIAPI_ADD_PARTY_REJ_indication, 0, api);
2449 }
2450 }
2451
2452 /*
2453 * Add-party.request from API in U4 or U10
2454 *
2455 * Q.2971:Call-Control-U 9-10/39 (U4)
2456 * Q.2971:Call-Control-U 21/39 (U10)
2457 * Q.2971:Call-Control-N 12/39 (N7)
2458 * Q.2971:Call-Control-N 22/39 (N10)
2459 */
2460 static void
2461 unx_add_party_request(struct call *c, struct uni_msg *msg, uint32_t cookie)
2462 {
2463 struct uniapi_add_party_request *add =
2464 uni_msg_rptr(msg, struct uniapi_add_party_request *);
2465 struct party *p;
2466
2467 if (IE_ISGOOD(add->add.epref)) {
2468 if (add->add.epref.flag != 0) {
2469 uni_msg_destroy(msg);
2470 uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2471 return;
2472 }
2473 p = uni_find_partyx(c, add->add.epref.epref, 1);
2474 if (p != NULL) {
2475 uni_msg_destroy(msg);
2476 uniapi_call_error(c, UNIAPI_ERROR_EPREF_INUSE, cookie);
2477 return;
2478 }
2479 } else if (!IE_ISPRESENT(add->add.epref)) {
2480 allocate_epref(c, &add->add.epref);
2481 if (!IE_ISPRESENT(add->add.epref)) {
2482 uni_msg_destroy(msg);
2483 uniapi_call_error(c, UNIAPI_ERROR_EPREF_INUSE, cookie);
2484 return;
2485 }
2486 } else {
2487 uni_msg_destroy(msg);
2488 uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2489 return;
2490 }
2491
2492 if ((p = uni_create_partyx(c, add->add.epref.epref, 1, cookie)) == NULL) {
2493 uni_msg_destroy(msg);
2494 uniapi_call_error(c, UNIAPI_ERROR_NOMEM, cookie);
2495 return;
2496 }
2497 uni_enq_party(p, SIGP_ADD_PARTY_request, cookie, msg, NULL);
2498 }
2499
2500 /*
2501 * Add-party-ack.request from API in U10/N10
2502 *
2503 * Q.2971:Call-Control-U 21/39
2504 * Q.2971:Call-Control-N 22/39
2505 */
2506 static void
2507 un10_add_party_ack_request(struct call *c, struct uni_msg *msg, uint32_t cookie)
2508 {
2509 struct uniapi_add_party_ack_request *ack =
2510 uni_msg_rptr(msg, struct uniapi_add_party_ack_request *);
2511 struct party *p;
2512
2513 if (!IE_ISGOOD(ack->ack.epref)) {
2514 uni_msg_destroy(msg);
2515 uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2516 return;
2517 }
2518 if (ack->ack.epref.flag != 1) {
2519 uni_msg_destroy(msg);
2520 uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2521 return;
2522 }
2523 if ((p = uni_find_partyx(c, ack->ack.epref.epref, 0)) == NULL) {
2524 uni_msg_destroy(msg);
2525 uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
2526 return;
2527 }
2528
2529 uni_enq_party(p, SIGP_ADD_PARTY_ACK_request, cookie, msg, NULL);
2530 }
2531
2532 /*
2533 * Party-alerting.request from API in U7/U8/U10
2534 *
2535 * Q.2971:Call-Control-U 14/39 U7
2536 * Q.2971:Call-Control-U 15/39 U8
2537 * Q.2971:Call-Control-U 21/39 U10
2538 * Q.2971:Call-Control-N 8/39 N4
2539 * Q.2971:Call-Control-N 22/39 N10
2540 */
2541 static void
2542 unx_party_alerting_request(struct call *c, struct uni_msg *msg, uint32_t cookie)
2543 {
2544 struct uniapi_party_alerting_request *alert =
2545 uni_msg_rptr(msg, struct uniapi_party_alerting_request *);
2546 struct party *p;
2547
2548 if (!IE_ISGOOD(alert->alert.epref)) {
2549 uni_msg_destroy(msg);
2550 uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2551 return;
2552 }
2553 if (alert->alert.epref.flag != 1) {
2554 uni_msg_destroy(msg);
2555 uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2556 return;
2557 }
2558 if ((p = uni_find_partyx(c, alert->alert.epref.epref, 0)) == NULL) {
2559 uni_msg_destroy(msg);
2560 uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
2561 return;
2562 }
2563
2564 uni_enq_party(p, SIGP_PARTY_ALERTING_request, cookie, msg, NULL);
2565 }
2566
2567 /*
2568 * Add-party-rej.request from API in U7/U8/U10/N4/N10
2569 *
2570 * Q.2971:Call-Control-U 14/39 U7
2571 * Q.2971:Call-Control-U 15/39 U8
2572 * Q.2971:Call-Control-U 21/39 U10
2573 * Q.2971:Call-Control-N 8/39 N4
2574 * Q.2971:Call-Control-N 22/39 N10
2575 */
2576 static void
2577 unx_add_party_rej_request(struct call *c, struct uni_msg *msg, uint32_t cookie)
2578 {
2579 struct uniapi_add_party_rej_request *rej =
2580 uni_msg_rptr(msg, struct uniapi_add_party_rej_request *);
2581 struct party *p;
2582
2583 if (!IE_ISGOOD(rej->rej.epref)) {
2584 uni_msg_destroy(msg);
2585 uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2586 return;
2587 }
2588 if (rej->rej.epref.flag != 1) {
2589 uni_msg_destroy(msg);
2590 uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2591 return;
2592 }
2593 if ((p = uni_find_partyx(c, rej->rej.epref.epref, 0)) == NULL) {
2594 uni_msg_destroy(msg);
2595 uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
2596 return;
2597 }
2598
2599 uni_enq_party(p, SIGP_ADD_PARTY_REJ_request, cookie, msg, NULL);
2600 }
2601
2602 /*
2603 * Drop-party.request from API in U1-U10
2604 *
2605 * Q.2971:Call-Control-U 21/39 U10
2606 * Q.2971:Call-Control-U 26/39 U1-U9
2607 * Q.2971:Call-Control-N 22/39 N10
2608 * Q.2971:Call-Control-N 27/39 N1-N9
2609 */
2610 static void
2611 unx_drop_party_request(struct call *c, struct uni_msg *msg, uint32_t cookie)
2612 {
2613 struct uniapi_drop_party_request *drop =
2614 uni_msg_rptr(msg, struct uniapi_drop_party_request *);
2615 struct party *p;
2616
2617 if (!IE_ISGOOD(drop->drop.epref)) {
2618 uni_msg_destroy(msg);
2619 uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2620 return;
2621 }
2622 if ((p = uni_find_partyx(c, drop->drop.epref.epref, !drop->drop.epref.flag)) == NULL) {
2623 uni_msg_destroy(msg);
2624 uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
2625 return;
2626 }
2627
2628 uni_enq_party(p, SIGP_DROP_PARTY_request, cookie, msg, NULL);
2629 }
2630
2631 /*
2632 * Drop-party-ack.request from API in U1-U10
2633 *
2634 * Q.2971:Call-Control-U 21/39 U10
2635 * Q.2971:Call-Control-U 26/39 U1-U9
2636 * Q.2971:Call-Control-N 22/39 N10
2637 * Q.2971:Call-Control-N 27/39 N1-N9
2638 */
2639 static void
2640 unx_drop_party_ack_request(struct call *c, struct uni_msg *msg,
2641 uint32_t cookie)
2642 {
2643 struct uniapi_drop_party_ack_request *ack =
2644 uni_msg_rptr(msg, struct uniapi_drop_party_ack_request *);
2645 struct party *p;
2646
2647 if (!IE_ISGOOD(ack->ack.epref)) {
2648 uni_msg_destroy(msg);
2649 uniapi_call_error(c, UNIAPI_ERROR_BAD_IE, cookie);
2650 return;
2651 }
2652 if ((p = uni_find_partyx(c, ack->ack.epref.epref, !ack->ack.epref.flag)) == NULL) {
2653 uni_msg_destroy(msg);
2654 uniapi_call_error(c, UNIAPI_ERROR_BAD_PARTY, cookie);
2655 return;
2656 }
2657
2658 uni_enq_party(p, SIGP_DROP_PARTY_ACK_request, cookie, msg, NULL);
2659 }
2660
2661 /*
2662 * ADD PARTY in U7/U8/U10
2663 *
2664 * Q.2971:Call-Control-U 14/39 U7
2665 * Q.2971:Call-Control-U 15/39 U8
2666 * Q.2971:Call-Control-U 21/39 U10
2667 * Q.2971:Call-Control-N 8/39 N4
2668 * Q.2971:Call-Control-N 21/39 N10
2669 *
2670 * Body already decoded
2671 * XXX check EPREF flag
2672 */
2673 static void
2674 unx_add_party(struct call *c, struct uni_msg *m, struct uni_all *u,
2675 int legal)
2676 {
2677 struct uni_all *resp;
2678 struct uni_ierr *e1;
2679 struct party *p = NULL;
2680 enum verify vfy;
2681
2682 uni_mandate_epref(c->uni, &u->u.add_party.epref);
2683 MANDATE_IE(c->uni, u->u.add_party.called, UNI_IE_CALLED);
2684
2685 /*
2686 * Do part of the verify handish: according to 9.5.7.2 we must send
2687 * an ADD_PARTY_REJ if mandatory IEs are bad or missing instead of
2688 * clearing the call. But we must send a STATUS, if it is the EPREF!
2689 */
2690 if (IE_ISGOOD(u->u.add_party.epref)) {
2691 c->uni->cause.u.ie.len = 0;
2692 FOREACH_ERR(e1, c->uni) {
2693 if (e1->err == UNI_IERR_MIS) {
2694 MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER,
2695 UNI_CAUSE_MANDAT);
2696 goto rej;
2697 }
2698 }
2699 FOREACH_ERR(e1, c->uni) {
2700 if (e1->man && e1->ie != UNI_IE_EPREF &&
2701 e1->act == UNI_IEACT_DEFAULT) {
2702 MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER,
2703 UNI_CAUSE_IE_INV);
2704 rej:
2705 uni_vfy_collect_ies(c->uni);
2706 if ((resp = UNI_ALLOC()) != NULL) {
2707 MK_MSG_RESP(resp, UNI_ADD_PARTY_REJ,
2708 &u->u.hdr.cref);
2709 MK_IE_EPREF(resp->u.add_party_rej.epref,
2710 u->u.add_party.epref.epref,
2711 !u->u.add_party.epref.flag);
2712 resp->u.add_party_rej.cause =
2713 c->uni->cause;
2714
2715 unx_send_add_party_rej(c, resp);
2716 }
2717 goto ignore;
2718 }
2719 }
2720 p = uni_find_partyx(c, u->u.add_party.epref.epref,
2721 u->u.add_party.epref.flag);
2722 }
2723
2724 vfy = uni_verify(c->uni, u->u.hdr.act);
2725
2726 switch (vfy) {
2727
2728 case VFY_CLR:
2729 uni_vfy_collect_ies(c->uni);
2730 clear_callD(c);
2731 goto ignore;
2732
2733 case VFY_RAIM:
2734 case VFY_RAI:
2735 uni_respond_status_verify(c->uni, &u->u.hdr.cref,
2736 map_callstate(c->cstate), &u->u.add_party.epref,
2737 p ? p->state : UNI_EPSTATE_NULL);
2738 /* FALLTHRU */
2739 case VFY_I:
2740 goto ignore;
2741
2742 case VFY_RAP:
2743 case VFY_RAPU:
2744 uni_respond_status_verify(c->uni, &u->u.hdr.cref,
2745 map_callstate(c->cstate), &u->u.add_party.epref,
2746 UNI_EPSTATE_ADD_RCVD);
2747 case VFY_OK:
2748 /* FALLTHRU */
2749 break;
2750 }
2751 if (!legal) {
2752 uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
2753 &u->u.add_party.epref, -1);
2754 return;
2755 }
2756
2757 if (IE_ISGOOD(u->u.add_party.epref) && p == NULL &&
2758 u->u.add_party.epref.flag) {
2759 IE_SETERROR(u->u.add_party.epref);
2760 (void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF,
2761 u->u.add_party.epref.h.act, UNI_IERR_BAD);
2762 }
2763
2764 if (!IE_ISGOOD(u->u.add_party.epref)) {
2765 /* 9.5.3.2.2 */
2766 if (vfy == VFY_OK) {
2767 MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER,
2768 UNI_CAUSE_IE_INV);
2769
2770 uni_respond_status_verify(c->uni, &u->u.hdr.cref,
2771 map_callstate(c->cstate), NULL, 0);
2772 }
2773 goto ignore;
2774 }
2775
2776
2777 if (p == NULL && (p = uni_create_party(c, &u->u.add_party.epref))
2778 == NULL)
2779 goto ignore;
2780
2781 uni_enq_party(p, SIGP_ADD_PARTY, 0, m, u);
2782 return;
2783
2784 ignore:
2785 uni_msg_destroy(m);
2786 UNI_FREE(u);
2787 }
2788
2789 /*
2790 * ADD PARTY ACKNOWLEDGE
2791 *
2792 * Q.2971:Call-Control-U 21/39 U10
2793 * Q.2971:Call-Control-N 15/39 N8
2794 * Q.2971:Call-Control-N 22/39 N10
2795 */
2796 static void
2797 un10n8_add_party_ack(struct call *c, struct uni_msg *m, struct uni_all *u,
2798 int legal)
2799 {
2800 struct party *p = NULL;
2801
2802 if (IE_ISGOOD(u->u.add_party_ack.epref)) {
2803 if (u->u.add_party_ack.epref.flag == 0) {
2804 IE_SETERROR(u->u.add_party_ack.epref);
2805 (void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF,
2806 u->u.add_party_ack.epref.h.act, UNI_IERR_BAD);
2807 } else {
2808 p = uni_find_partyx(c, u->u.add_party_ack.epref.epref, 1);
2809 if (p == NULL) {
2810 respond_drop_party_ack(c,
2811 &u->u.add_party_ack.epref,
2812 UNI_CAUSE_ENDP_INV);
2813 goto ignore;
2814 }
2815 }
2816 }
2817 uni_mandate_epref(c->uni, &u->u.add_party_ack.epref);
2818
2819 switch (uni_verify(c->uni, u->u.hdr.act)) {
2820
2821 case VFY_CLR:
2822 uni_vfy_collect_ies(c->uni);
2823 clear_callD(c);
2824 goto ignore;
2825
2826 case VFY_RAIM:
2827 case VFY_RAI:
2828 report:
2829 uni_respond_status_verify(c->uni, &u->u.hdr.cref,
2830 map_callstate(c->cstate), &u->u.add_party_ack.epref,
2831 p ? p->state : UNI_EPSTATE_NULL);
2832 case VFY_I:
2833 goto ignore;
2834
2835 case VFY_RAP:
2836 case VFY_RAPU:
2837 uni_respond_status_verify(c->uni, &u->u.hdr.cref,
2838 map_callstate(c->cstate), &u->u.add_party_ack.epref,
2839 p ? UNI_EPSTATE_ACTIVE : UNI_EPSTATE_NULL);
2840 if (!IE_ISGOOD(u->u.party_alerting.epref))
2841 /* See below */
2842 goto ignore;
2843 break;
2844 case VFY_OK:
2845 if (!IE_ISGOOD(u->u.party_alerting.epref))
2846 /* this happens when the EPREF has bad format.
2847 * The rules require us the message to be ignored
2848 * (9.5.3.2.2e) and to report status.
2849 */
2850 goto report;
2851 break;
2852 }
2853 if (legal) {
2854 /* p is != NULL here */
2855 uni_enq_party(p, SIGP_ADD_PARTY_ACK, 0, m, u);
2856 return;
2857 }
2858 if (p == NULL)
2859 /* Q.2971 9.5.3.2.3a) */
2860 respond_drop_party_ack(c, &u->u.add_party_ack.epref,
2861 UNI_CAUSE_ENDP_INV);
2862 else
2863 uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
2864 &u->u.add_party_ack.epref, p->state);
2865
2866 ignore:
2867 uni_msg_destroy(m);
2868 UNI_FREE(u);
2869 }
2870
2871 /*
2872 * Make the EPREF action default
2873 */
2874 static void
2875 default_act_epref(struct uni *uni, struct uni_ie_epref *epref)
2876 {
2877 struct uni_ierr *e;
2878
2879 FOREACH_ERR(e, uni)
2880 if (e->ie == UNI_IE_EPREF) {
2881 e->act = UNI_IEACT_DEFAULT;
2882 break;
2883 }
2884 epref->h.act = UNI_IEACT_DEFAULT;
2885 }
2886
2887 /*
2888 * PARTY ALERTING message
2889 *
2890 * Q.2971:Call-Control-U 9/39 U4
2891 * Q.2971:Call-Control-U 21/39 U10
2892 * Q.2971:Call-Control-N 12/39 N7
2893 * Q.2971:Call-Control-N 15/39 N8
2894 * Q.2971:Call-Control-N 22/39 N10
2895 */
2896 static void
2897 unx_party_alerting(struct call *c, struct uni_msg *m, struct uni_all *u,
2898 int legal)
2899 {
2900 struct party *p = NULL;
2901
2902 if (IE_ISGOOD(u->u.party_alerting.epref)) {
2903 if (u->u.party_alerting.epref.flag == 0) {
2904 IE_SETERROR(u->u.party_alerting.epref);
2905 (void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF,
2906 u->u.party_alerting.epref.h.act, UNI_IERR_BAD);
2907 } else {
2908 p = uni_find_partyx(c, u->u.party_alerting.epref.epref, 1);
2909 if (p == NULL) {
2910 respond_drop_party_ack(c,
2911 &u->u.party_alerting.epref,
2912 UNI_CAUSE_ENDP_INV);
2913 goto ignore;
2914 }
2915 }
2916 }
2917 uni_mandate_epref(c->uni, &u->u.party_alerting.epref);
2918
2919 switch (uni_verify(c->uni, u->u.hdr.act)) {
2920
2921 case VFY_CLR:
2922 uni_vfy_collect_ies(c->uni);
2923 clear_callD(c);
2924 goto ignore;
2925
2926 case VFY_RAIM:
2927 case VFY_RAI:
2928 report:
2929 uni_respond_status_verify(c->uni, &u->u.hdr.cref,
2930 map_callstate(c->cstate), &u->u.party_alerting.epref,
2931 p ? p->state : UNI_EPSTATE_NULL);
2932 case VFY_I:
2933 goto ignore;
2934
2935 case VFY_RAP:
2936 case VFY_RAPU:
2937 uni_respond_status_verify(c->uni, &u->u.hdr.cref,
2938 map_callstate(c->cstate), &u->u.party_alerting.epref,
2939 p ? UNI_EPSTATE_ALERT_RCVD : UNI_EPSTATE_NULL);
2940 if (!IE_ISGOOD(u->u.party_alerting.epref))
2941 /* See below */
2942 goto ignore;
2943 break;
2944
2945 case VFY_OK:
2946 if (!IE_ISGOOD(u->u.party_alerting.epref))
2947 /* The rules require us the message to be ignored
2948 * (9.5.3.2.2e) and to report status.
2949 */
2950 goto report;
2951 break;
2952 }
2953 if (legal) {
2954 /* p is != NULL here */
2955 uni_enq_party(p, SIGP_PARTY_ALERTING, 0, m, u);
2956 return;
2957 }
2958 if (p == NULL)
2959 /* Q.2971 9.5.3.2.3a) */
2960 respond_drop_party_ack(c, &u->u.party_alerting.epref,
2961 UNI_CAUSE_ENDP_INV);
2962 else
2963 uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
2964 &u->u.party_alerting.epref, p->state);
2965
2966 ignore:
2967 uni_msg_destroy(m);
2968 UNI_FREE(u);
2969 }
2970
2971 /*
2972 * Handle a bad/missing cause in a DROP_PARTY_ACK or ADD_PARTY_REJ
2973 *
2974 * If the IE is missing or bad and the action is defaulted handle as
2975 * cause #1 according to 9.5.7.1/2.
2976 * Otherwise keep the IE.
2977 */
2978 static void
2979 handle_bad_drop_cause(struct call *c, struct uni_ie_cause *cause, int mkcause)
2980 {
2981
2982 if (IE_ISGOOD(*cause))
2983 return;
2984
2985 if (!IE_ISPRESENT(*cause)) {
2986 /* 9.5.7.1 */
2987 /* cannot make cause here because we need the 96 error */
2988 uni_vfy_remove_cause(c->uni);
2989 return;
2990 }
2991 if (cause->h.act != UNI_IEACT_DEFAULT)
2992 return;
2993
2994 /* 9.5.7.2 */
2995 uni_vfy_remove_cause(c->uni);
2996 if (mkcause)
2997 MK_IE_CAUSE(*cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_UNSPEC);
2998 }
2999
3000 /*
3001 * ADD PARTY REJ from party control
3002 * Q.2971:Call-Control-U 21/39
3003 * Q.2971:Call-Control-U 24/39
3004 */
3005 static void
3006 unx_send_add_party_rej(struct call *c, struct uni_all *u)
3007 {
3008
3009 if (uni_party_act_count(c, 2) == 0) {
3010 if (c->cstate != CALLST_U11 && c->cstate != CALLST_N12) {
3011 c->uni->cause = u->u.add_party_rej.cause;
3012 clear_callD(c);
3013 }
3014 } else
3015 (void)uni_send_output(u, c->uni);
3016 UNI_FREE(u);
3017 }
3018
3019 /*
3020 * ADD_PARTY_REJECT in U4/U10
3021 *
3022 * Q.2971:Call-Control-U 9/39 U4
3023 * Q.2971:Call-Control-U 21/39 U10
3024 * Q.2971:Call-Control-N 12/39 N7
3025 * Q.2971:Call-Control-N 15/39 N8
3026 * Q.2971:Call-Control-N 22/39 N10
3027 */
3028 static void
3029 unx_add_party_rej(struct call *c, struct uni_msg *m, struct uni_all *u,
3030 int legal)
3031 {
3032 struct uni_add_party_rej *ar = &u->u.add_party_rej;
3033 struct party *p;
3034
3035 if (IE_ISGOOD(ar->epref)) {
3036 p = uni_find_partyx(c, ar->epref.epref, ar->epref.flag);
3037 if (p == NULL)
3038 goto ignore;
3039
3040 if (legal) {
3041 handle_bad_drop_cause(c, &ar->cause, 0);
3042 uni_vfy_remove_unknown(c->uni);
3043 switch (uni_verify(c->uni, u->u.hdr.act)) {
3044
3045 case VFY_CLR:
3046 goto clear;
3047
3048 case VFY_RAIM:
3049 case VFY_RAI:
3050 uni_respond_status_verify(c->uni,
3051 &u->u.hdr.cref, map_callstate(c->cstate),
3052 &ar->epref, p->state);
3053 case VFY_I:
3054 goto ignore;
3055
3056 case VFY_RAPU:
3057 uni_vfy_collect_ies(c->uni);
3058 break;
3059
3060 case VFY_RAP:
3061 uni_respond_status_verify(c->uni,
3062 &u->u.hdr.cref, map_callstate(c->cstate),
3063 &ar->epref, p->state);
3064 case VFY_OK:
3065 break;
3066 }
3067 uni_enq_party(p, SIGP_ADD_PARTY_REJ, 0, m, u);
3068 return;
3069 }
3070 uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3071 &ar->epref, -1);
3072 return;
3073 }
3074
3075 /* Q.2971: 9.5.3.2.1 last paragraph
3076 * 9.5.3.2.2 second to last paragraph
3077 * Make the action indicator default.
3078 */
3079 default_act_epref(c->uni, &ar->epref);
3080 if (!IE_ISPRESENT(ar->epref))
3081 uni_mandate_ie(c->uni, UNI_IE_EPREF);
3082 (void)uni_verify(c->uni, u->u.hdr.act);
3083
3084 clear:
3085 uni_vfy_collect_ies(c->uni);
3086 clear_callD(c);
3087
3088 ignore:
3089 uni_msg_destroy(m);
3090 UNI_FREE(u);
3091 }
3092
3093 /*
3094 * DROP_PARTY
3095 *
3096 * Q.2971:Call-Control-U 26/39 Ux
3097 * Q.2971:Call-Control-U 21/39 U10
3098 * Q.2971:Call-Control-N 27/39 Nx
3099 * Q.2971:Call-Control-N 22/39 N10
3100 */
3101 static void
3102 unx_drop_party(struct call *c, struct uni_msg *m, struct uni_all *u, int legal)
3103 {
3104 struct uni_drop_party *dp = &u->u.drop_party;
3105 struct party *p;
3106 struct uni_ierr *e;
3107
3108 if (IE_ISGOOD(dp->epref)) {
3109 p = uni_find_partyx(c, dp->epref.epref, dp->epref.flag);
3110 if (p == NULL) {
3111 respond_drop_party_ack(c, &dp->epref,
3112 UNI_CAUSE_ENDP_INV);
3113 goto ignore;
3114 }
3115 handle_bad_drop_cause(c, &dp->cause, 0);
3116 uni_vfy_remove_unknown(c->uni);
3117 switch (uni_verify(c->uni, u->u.hdr.act)) {
3118
3119 case VFY_CLR:
3120 goto clear;
3121
3122 case VFY_RAIM:
3123 case VFY_RAI:
3124 uni_respond_status_verify(c->uni, &u->u.hdr.cref,
3125 map_callstate(c->cstate),
3126 &u->u.drop_party.epref, p->state);
3127 case VFY_I:
3128 goto ignore;
3129
3130 case VFY_RAPU:
3131 uni_vfy_collect_ies(c->uni);
3132 break;
3133
3134 case VFY_RAP:
3135 uni_respond_status_verify(c->uni, &u->u.hdr.cref,
3136 map_callstate(c->cstate),
3137 &dp->epref, UNI_EPSTATE_DROP_RCVD);
3138 case VFY_OK:
3139 break;
3140 }
3141 if (legal) {
3142 uni_enq_party(p, SIGP_DROP_PARTY, 0, m, u);
3143 return;
3144 }
3145 uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, &dp->epref, -1);
3146 goto ignore;
3147 }
3148
3149 /* Q.2971: 9.5.3.2.1 last paragraph
3150 * 9.5.3.2.2 second to last paragraph
3151 * Make the action indicator default.
3152 */
3153 FOREACH_ERR(e, c->uni)
3154 if (e->ie == UNI_IE_EPREF) {
3155 e->act = UNI_IEACT_DEFAULT;
3156 break;
3157 }
3158 dp->epref.h.act = UNI_IEACT_DEFAULT;
3159
3160 if (!IE_ISPRESENT(dp->epref))
3161 uni_mandate_ie(c->uni, UNI_IE_EPREF);
3162 (void)uni_verify(c->uni, u->u.hdr.act);
3163
3164 clear:
3165 uni_vfy_collect_ies(c->uni);
3166 clear_callD(c);
3167 uni_msg_destroy(m);
3168 UNI_FREE(u);
3169 return;
3170
3171 ignore:
3172 uni_msg_destroy(m);
3173 UNI_FREE(u);
3174 }
3175
3176 /*
3177 * DROP_PARTY_ACK
3178 *
3179 * Q.2971:Call-Control-U 26/39 Ux
3180 * Q.2971:Call-Control-U 21/39 U10
3181 * Q.2971:Call-Control-N 27/39 Nx
3182 * Q.2971:Call-Control-N 22/39 N10
3183 */
3184 static void
3185 unx_drop_party_ack(struct call *c, struct uni_msg *m, struct uni_all *u,
3186 int legal)
3187 {
3188 struct party *p;
3189 struct uni_drop_party_ack *ack = &u->u.drop_party_ack;
3190
3191 if (IE_ISGOOD(u->u.drop_party_ack.epref)) {
3192 p = uni_find_partyx(c, ack->epref.epref, ack->epref.flag);
3193 if (p != NULL) {
3194 handle_bad_drop_cause(c, &ack->cause, 1);
3195 uni_vfy_remove_unknown(c->uni);
3196 switch (uni_verify(c->uni, u->u.hdr.act)) {
3197
3198 case VFY_CLR:
3199 goto clear;
3200
3201 case VFY_RAIM:
3202 case VFY_RAI:
3203 uni_respond_status_verify(c->uni,
3204 &u->u.hdr.cref, map_callstate(c->cstate),
3205 &ack->epref, p->state);
3206 case VFY_I:
3207 goto ignore;
3208
3209 case VFY_RAP:
3210 uni_respond_status_verify(c->uni,
3211 &u->u.hdr.cref, map_callstate(c->cstate),
3212 &ack->epref, UNI_EPSTATE_NULL);
3213 case VFY_RAPU:
3214 case VFY_OK:
3215 break;
3216 }
3217 if (legal) {
3218 uni_enq_party(p, SIGP_DROP_PARTY_ACK, 0, m, u);
3219 return;
3220 }
3221 uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3222 &ack->epref, -1);
3223 }
3224 goto ignore;
3225 }
3226
3227 /* Q.2971: 9.5.3.2.1 last paragraph
3228 * 9.5.3.2.2 second to last paragraph
3229 */
3230 (void)uni_verify(c->uni, u->u.hdr.act);
3231 MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, UNI_CAUSE_IE_INV);
3232
3233 clear:
3234 uni_vfy_collect_ies(c->uni);
3235 clear_callD(c);
3236 uni_msg_destroy(m);
3237 UNI_FREE(u);
3238 return;
3239
3240 ignore:
3241 uni_msg_destroy(m);
3242 UNI_FREE(u);
3243 }
3244
3245 /**********************************************************************/
3246
3247 /*
3248 * Bad or unrecognized message.
3249 *
3250 * Q.2971:Call-Control-U 35/39
3251 */
3252 void
3253 uni_bad_message(struct call *c, struct uni_all *u, u_int cause,
3254 struct uni_ie_epref *epref, int ps)
3255 {
3256 struct uni_all *resp;
3257 struct party *p;
3258
3259 if ((u->u.hdr.act == UNI_MSGACT_CLEAR &&
3260 (c->cstate == CALLST_U11 ||
3261 c->cstate == CALLST_U12 ||
3262 c->cstate == CALLST_N11 ||
3263 c->cstate == CALLST_N12)) ||
3264 u->u.hdr.act == UNI_MSGACT_IGNORE)
3265 return;
3266
3267 MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER, cause);
3268 ADD_CAUSE_MTYPE(c->uni->cause, u->mtype);
3269
3270 if (u->u.hdr.act == UNI_MSGACT_CLEAR) {
3271 clear_callD(c);
3272 return;
3273 }
3274
3275 /*
3276 * Send STATUS
3277 */
3278 if ((resp = UNI_ALLOC()) != NULL) {
3279 MK_MSG_RESP(resp, UNI_STATUS, &u->u.hdr.cref);
3280 MK_IE_CALLSTATE(resp->u.status.callstate,
3281 map_callstate(c->cstate));
3282 resp->u.status.cause = c->uni->cause;
3283
3284 if (epref != NULL && IE_ISGOOD(*epref)) {
3285 MK_IE_EPREF(resp->u.status.epref, epref->epref, !epref->flag);
3286 if (ps == -1) {
3287 p = uni_find_party(c, epref);
3288 if (p == NULL)
3289 ps = UNI_EPSTATE_NULL;
3290 else
3291 ps = p->state;
3292 }
3293 MK_IE_EPSTATE(resp->u.status.epstate, ps);
3294 }
3295 (void)uni_send_output(resp, c->uni);
3296
3297 UNI_FREE(resp);
3298 }
3299 }
3300
3301 /**********************************************************************/
3302
3303 /*
3304 * Unknown message in any state.
3305 *
3306 * Q.2971:Call-Control 35/39
3307 * Q.2971:Call-Control 36/39
3308 */
3309 static void
3310 unx_unknown(struct call *c, struct uni_msg *m, struct uni_all *u)
3311 {
3312 /*
3313 * Unrecognized message. Cannot call verify here, because
3314 * it doesn't know about unrecognized messages.
3315 */
3316 if (u->u.hdr.act == UNI_MSGACT_CLEAR) {
3317 MK_IE_CAUSE(c->uni->cause, UNI_CAUSE_LOC_USER,
3318 UNI_CAUSE_MTYPE_NIMPL);
3319 ADD_CAUSE_MTYPE(c->uni->cause, u->mtype);
3320 clear_callD(c);
3321 } else if(u->u.hdr.act == UNI_MSGACT_IGNORE) {
3322 ;
3323 } else {
3324 (void)uni_decode_body(m, u, &c->uni->cx);
3325 uni_bad_message(c, u, UNI_CAUSE_MTYPE_NIMPL,
3326 &u->u.unknown.epref, -1);
3327 }
3328 uni_msg_destroy(m);
3329 UNI_FREE(u);
3330 }
3331 /**********************************************************************/
3332
3333 void
3334 uni_sig_call(struct call *c, enum call_sig sig, uint32_t cookie,
3335 struct uni_msg *msg, struct uni_all *u)
3336 {
3337 if (sig >= SIGC_END) {
3338 VERBOSE(c->uni, UNI_FAC_ERR, 1,
3339 "Signal %d outside of range to Call-Control", sig);
3340 if (msg)
3341 uni_msg_destroy(msg);
3342 if (u)
3343 UNI_FREE(u);
3344 return;
3345 }
3346
3347 VERBOSE(c->uni, UNI_FAC_CALL, 1, "Signal %s in state %s of call %u/%s"
3348 "; cookie %u", call_sigs[sig], callstates[c->cstate].name, c->cref,
3349 c->mine ? "mine" : "his", cookie);
3350
3351 switch (sig) {
3352
3353 case SIGC_LINK_RELEASE_indication:
3354 if (c->cstate == CALLST_U10 || c->cstate == CALLST_N10)
3355 /* Q.2971:Call-Control-U 36/39 */
3356 /* Q.2971:Call-Control-N 20/39 */
3357 un10_link_release_indication(c);
3358 else
3359 /* Q.2971:Call-Control-U 36/39 */
3360 /* Q.2971:Call-Control-N 37/39 */
3361 unx_link_release_indication(c);
3362 break;
3363
3364 case SIGC_LINK_ESTABLISH_ERROR_indication:
3365 if (c->cstate != CALLST_U10 && c->cstate != CALLST_N10) {
3366 VERBOSE(c->uni, UNI_FAC_ERR, 1,
3367 "link-establish-error.indication in cs=%s",
3368 callstates[c->cstate].name);
3369 break;
3370 }
3371 /* Q.2971:Call-Control-U 19/39 */
3372 /* Q.2971:Call-Control-N 20/39 */
3373 un10_link_establish_error_indication(c);
3374 break;
3375
3376 case SIGC_LINK_ESTABLISH_indication:
3377 switch (c->cstate) {
3378
3379 case CALLST_U1: case CALLST_N1:
3380 case CALLST_U3: case CALLST_N3:
3381 case CALLST_U4: case CALLST_N4:
3382 case CALLST_U6: case CALLST_N6:
3383 case CALLST_U7: case CALLST_N7:
3384 case CALLST_U8: case CALLST_N8:
3385 case CALLST_U9: case CALLST_N9:
3386 /* Q.2971:Call-Control-U 36/39 */
3387 /* Q.2971:Call-Control-N 37/39 */
3388 unx_link_establish_indication(c);
3389 break;
3390
3391 case CALLST_U10: case CALLST_N10:
3392 /* Q.2971:Call-Control-U 19/39 */
3393 /* Q.2971:Call-Control-N 20/39 */
3394 un10_link_establish_indication(c);
3395 break;
3396
3397 case CALLST_U11: case CALLST_N11:
3398 case CALLST_U12: case CALLST_N12:
3399 /* Q.2971:Call-Control-U 36/39 */
3400 /* Q.2971:Call-Control-N 37/39 */
3401 break;
3402
3403 default:
3404 VERBOSE(c->uni, UNI_FAC_ERR, 1,
3405 "link-establish.indication in cs=%s",
3406 callstates[c->cstate].name);
3407 }
3408 break;
3409
3410 case SIGC_LINK_ESTABLISH_confirm:
3411 if (c->cstate != CALLST_U10 && c->cstate != CALLST_N10) {
3412 VERBOSE(c->uni, UNI_FAC_ERR, 1,
3413 "link-establish.confirm in cs=%s",
3414 callstates[c->cstate].name);
3415 break;
3416 }
3417 /* Q.2971:Call-Control-U 19/39 */
3418 /* Q.2971:Call-Control-N 20/39 */
3419 un10_link_establish_confirm(c);
3420 break;
3421
3422 case SIGC_UNKNOWN:
3423 /* Q.2971:Call-Control 35/39 */
3424 /* Q.2971:Call-Control 36/39 */
3425 unx_unknown(c, msg, u);
3426 break;
3427
3428 case SIGC_SETUP:
3429 if (c->cstate != CALLST_NULL) {
3430 (void)uni_decode_body(msg, u, &c->uni->cx);
3431 uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3432 &u->u.setup.epref, -1);
3433 goto drop;
3434 }
3435 if (c->uni->proto == UNIPROTO_UNI40N)
3436 /* Q.2971:Call-Control-N 4/39 */
3437 un0_setup(c, msg, u, CALLST_N1);
3438 else
3439 /* Q.2971:Call-Control-U 4/39 */
3440 un0_setup(c, msg, u, CALLST_U6);
3441 break;
3442
3443 case SIGC_CALL_PROC:
3444 if (c->cstate == CALLST_U1) {
3445 /* Q.2971:Call-Control-U 6/39 */
3446 u1n6_call_proc(c, msg, u, CALLST_U3);
3447 break;
3448 }
3449 if (c->cstate == CALLST_N6) {
3450 /* Q.2971:Call-Control-N 11/39 */
3451 u1n6_call_proc(c, msg, u, CALLST_N9);
3452 break;
3453 }
3454 (void)uni_decode_body(msg, u, &c->uni->cx);
3455 uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3456 &u->u.call_proc.epref, -1);
3457 goto drop;
3458
3459 case SIGC_ALERTING:
3460 if (c->cstate == CALLST_U1 || c->cstate == CALLST_U3) {
3461 /* Q.2971:Call-Control-U 37/39 (U1) */
3462 /* Q.2971:Call-Control-U 7/39 (U3) */
3463 unx_alerting(c, msg, u, CALLST_U4);
3464 break;
3465 }
3466 if (c->cstate == CALLST_N6) {
3467 /* Q.2971:Call-Control-N 9/39 (N6) */
3468 /* Q.2971:Call-Control-N 17/39 (N9) */
3469 unx_alerting(c, msg, u, CALLST_N7);
3470 break;
3471 }
3472 (void)uni_decode_body(msg, u, &c->uni->cx);
3473 uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3474 &u->u.alerting.epref, -1);
3475 goto drop;
3476
3477 case SIGC_CONNECT:
3478 if (c->cstate == CALLST_U1 || c->cstate == CALLST_U3 ||
3479 c->cstate == CALLST_U4) {
3480 /* Q.2971:Call-Control-U 7-8/39 (U3) */
3481 /* Q.2971:Call-Control-U 11/39 (U4) */
3482 /* Q.2971:Call-Control-U 37/39 (U1) */
3483 unx_connect(c, msg, u, CALLST_U10);
3484 break;
3485 }
3486 if (c->cstate == CALLST_N6 || c->cstate == CALLST_N7 ||
3487 c->cstate == CALLST_N9) {
3488 /* Q.2971:Call-Control-N 9-10/39 (N6) */
3489 /* Q.2971:Call-Control-N 14/39 (N7) */
3490 /* Q.2971:Call-Control-N 17/39 (N9) */
3491 unx_connect(c, msg, u, CALLST_N8);
3492 break;
3493 }
3494 (void)uni_decode_body(msg, u, &c->uni->cx);
3495 uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3496 &u->u.connect.epref, -1);
3497 goto drop;
3498
3499 case SIGC_CONNECT_ACK:
3500 if (c->cstate == CALLST_U8) {
3501 /* Q.2971:Call-Control-U 15-16/39 */
3502 u8_connect_ack(c, msg, u, CALLST_U10);
3503 break;
3504 }
3505 if (c->cstate == CALLST_N10) {
3506 /* Q.2971:Call-Control-N 18/39 */
3507 n10_connect_ack(c, msg, u);
3508 break;
3509 }
3510 uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, NULL, 0);
3511 goto drop;
3512
3513 case SIGC_RELEASE:
3514 switch (c->cstate) {
3515
3516 default:
3517 uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP, NULL, 0);
3518 goto drop;
3519
3520 case CALLST_U11:
3521 case CALLST_N12:
3522 /* Q.2971:Call-Control-U 28/39 */
3523 /* Q.2971:Call-Control-N 30/39 */
3524 u11n12_release(c, msg, u);
3525 break;
3526
3527 case CALLST_U1:
3528 case CALLST_U3:
3529 case CALLST_U4:
3530 case CALLST_U6:
3531 case CALLST_U7:
3532 case CALLST_U8:
3533 case CALLST_U9:
3534 case CALLST_U10:
3535 case CALLST_U12:
3536 /* Q.2971:Call-Control-U 25/39 */
3537 unx_release(c, msg, u, CALLST_U12);
3538 break;
3539
3540 case CALLST_N1:
3541 case CALLST_N3:
3542 case CALLST_N4:
3543 case CALLST_N6:
3544 case CALLST_N7:
3545 case CALLST_N8:
3546 case CALLST_N9:
3547 case CALLST_N10:
3548 case CALLST_N11:
3549 /* Q.2971:Call-Control-N 26/39 */
3550 unx_release(c, msg, u, CALLST_N11);
3551 break;
3552 }
3553 break;
3554
3555 case SIGC_RELEASE_COMPL:
3556 /* Q.2971:Call-Control-U 25/39 */
3557 /* Q.2971:Call-Control-N 26/39 */
3558 unx_release_compl(c, msg, u);
3559 break;
3560
3561 case SIGC_NOTIFY:
3562 /* Q.2971:Call-Control-U 18/39 */
3563 /* Q.2971:Call-Control-N 19/39 */
3564 unx_notify(c, msg, u);
3565 break;
3566
3567 case SIGC_STATUS:
3568 if (c->cstate == CALLST_U11 || c->cstate == CALLST_U12 ||
3569 c->cstate == CALLST_N11 || c->cstate == CALLST_N12) {
3570 /* Q.2971:Call-Control-U 29/39 (U11) */
3571 /* Q.2971:Call-Control-U 30/39 (U12) */
3572 /* Q.2971:Call-Control-N 29/39 (N11) */
3573 /* Q.2971:Call-Control-N 31/39 (N12) */
3574 un11un12_status(c, msg, u);
3575 break;
3576 }
3577 /* Q.2971:Call-Control-U 32/39 */
3578 /* Q.2971:Call-Control-N 33/39 */
3579 unx_status(c, msg, u);
3580 break;
3581
3582 case SIGC_STATUS_ENQ:
3583 /* Q.2971:Call-Control-U 31/39 */
3584 /* Q.2971:Call-Control-N 32/39 */
3585 unx_status_enq(c, msg, u);
3586 break;
3587
3588 case SIGC_ADD_PARTY:
3589 (void)uni_decode_body(msg, u, &c->uni->cx);
3590
3591 if (c->type != CALL_LEAF && c->type != CALL_ROOT) {
3592 uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3593 &u->u.add_party.epref, UNI_EPSTATE_NULL);
3594 goto drop;
3595 }
3596 switch (c->cstate) {
3597 case CALLST_U7:
3598 case CALLST_U8:
3599 case CALLST_U10:
3600 case CALLST_N4:
3601 case CALLST_N10:
3602 /* Q.2971:Call-Control-U 14/39 U7 */
3603 /* Q.2971:Call-Control-U 15/39 U8 */
3604 /* Q.2971:Call-Control-U 21/39 U10 */
3605 /* Q.2971:Call-Control-N 8/39 N4 */
3606 /* Q.2971:Call-Control-N 21/39 N10 */
3607 unx_add_party(c, msg, u, 1);
3608 break;
3609
3610 default:
3611 unx_add_party(c, msg, u, 0);
3612 goto drop;
3613 }
3614 break;
3615
3616 case SIGC_PARTY_ALERTING:
3617 (void)uni_decode_body(msg, u, &c->uni->cx);
3618
3619 if (c->type != CALL_ROOT) {
3620 uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3621 &u->u.party_alerting.epref, -1);
3622 goto drop;
3623 }
3624 switch (c->cstate) {
3625
3626 default:
3627 /* Q.2971 9.5.3.2.3a) */
3628 unx_party_alerting(c, msg, u, 0);
3629 break;
3630
3631 case CALLST_U4:
3632 case CALLST_U10:
3633 /* Q.2971:Call-Control-U 9/39 U4 */
3634 /* Q.2971:Call-Control-U 21/39 U10 */
3635 /* Q.2971:Call-Control-N 12/39 N7 */
3636 /* Q.2971:Call-Control-N 15/39 N8 */
3637 /* Q.2971:Call-Control-N 22/39 N10 */
3638 unx_party_alerting(c, msg, u, 1);
3639 break;
3640 }
3641 break;
3642
3643 case SIGC_ADD_PARTY_ACK:
3644 (void)uni_decode_body(msg, u, &c->uni->cx);
3645
3646 if (c->type != CALL_ROOT) {
3647 uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3648 &u->u.add_party_rej.epref, -1);
3649 goto drop;
3650 }
3651 switch (c->cstate) {
3652
3653 case CALLST_U10:
3654 /* Q.2971:Call-Control-U 21/39 U10 */
3655 /* Q.2971:Call-Control-N 15/39 N8 */
3656 /* Q.2971:Call-Control-N 22/39 N10 */
3657 un10n8_add_party_ack(c, msg, u, 1);
3658 break;
3659
3660 default:
3661 /* Q.2971 9.5.3.2.3a) */
3662 un10n8_add_party_ack(c, msg, u, 0);
3663 break;
3664 }
3665 break;
3666
3667 case SIGC_ADD_PARTY_REJ:
3668 (void)uni_decode_body(msg, u, &c->uni->cx);
3669
3670 if (c->type != CALL_ROOT) {
3671 uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3672 &u->u.add_party_rej.epref, -1);
3673 goto drop;
3674 }
3675 switch (c->cstate) {
3676
3677 case CALLST_U4:
3678 case CALLST_U10:
3679 case CALLST_N7:
3680 case CALLST_N8:
3681 case CALLST_N10:
3682 /* Q.2971:Call-Control-U 9/39 U4 */
3683 /* Q.2971:Call-Control-U 21/39 U10 */
3684 /* Q.2971:Call-Control-N 12/39 N7 */
3685 /* Q.2971:Call-Control-N 15/39 N8 */
3686 /* Q.2971:Call-Control-N 22/39 N10 */
3687 unx_add_party_rej(c, msg, u, 1);
3688 break;
3689
3690 default:
3691 /* Q.2971: 9.5.3.2.3b */
3692 unx_add_party_rej(c, msg, u, 0);
3693 break;
3694 }
3695 break;
3696
3697 case SIGC_DROP_PARTY:
3698 (void)uni_decode_body(msg, u, &c->uni->cx);
3699
3700 if (c->type != CALL_ROOT && c->type != CALL_LEAF) {
3701 uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3702 &u->u.drop_party.epref, -1);
3703 goto drop;
3704 }
3705 switch (c->cstate) {
3706 case CALLST_U11:
3707 case CALLST_U12:
3708 case CALLST_N11:
3709 case CALLST_N12:
3710 /* Q.2971:Call-Control-U 28/39 U11 */
3711 /* Q.2971:Call-Control-U 30/39 U12 */
3712 /* Q.2971:Call-Control-N 29/39 N11 */
3713 /* Q.2971:Call-Control-N 30/39 N12 */
3714 goto drop;
3715
3716 case CALLST_NULL:
3717 uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3718 &u->u.drop_party.epref, UNI_EPSTATE_NULL);
3719 goto drop;
3720
3721 case CALLST_U3:
3722 case CALLST_N3:
3723 /* L3MU_17_38 */
3724 unx_drop_party(c, msg, u, 0);
3725 break;
3726
3727 case CALLST_U8:
3728 if (c->uni->sb_tb) {
3729 /* L3MU_06_0[3-6] */
3730 unx_drop_party(c, msg, u, 0);
3731 break;
3732 }
3733 /* FALLTHRU */
3734
3735 default:
3736 /* Q.2971:Call-Control-U 26/39 Ux */
3737 /* Q.2971:Call-Control-U 21/39 U10 */
3738 /* Q.2971:Call-Control-N 27/39 Nx */
3739 /* Q.2971:Call-Control-N 21/39 N10 */
3740 unx_drop_party(c, msg, u, 1);
3741 break;
3742 }
3743 break;
3744
3745 case SIGC_DROP_PARTY_ACK:
3746 (void)uni_decode_body(msg, u, &c->uni->cx);
3747
3748 if (c->type != CALL_ROOT && c->type != CALL_LEAF) {
3749 uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3750 &u->u.drop_party_ack.epref, -1);
3751 goto drop;
3752 }
3753 switch (c->cstate) {
3754
3755 case CALLST_U11:
3756 case CALLST_U12:
3757 /* Q.2971:Call-Control-U 28/39 U11 */
3758 /* Q.2971:Call-Control-U 30/39 U12 */
3759 /* Q.2971:Call-Control-N 29/39 N11 */
3760 /* Q.2971:Call-Control-N 30/39 N12 */
3761 goto drop;
3762
3763 case CALLST_NULL:
3764 uni_bad_message(c, u, UNI_CAUSE_MSG_INCOMP,
3765 &u->u.drop_party.epref, UNI_EPSTATE_NULL);
3766 goto drop;
3767
3768 case CALLST_U4:
3769 case CALLST_N4:
3770 case CALLST_U7:
3771 case CALLST_N7:
3772 case CALLST_U8:
3773 case CALLST_N8:
3774 case CALLST_U10:
3775 case CALLST_N10:
3776 /* Q.2971:Call-Control-U 26/39 Ux */
3777 /* Q.2971:Call-Control-U 21/39 U10 */
3778 /* Q.2971:Call-Control-N 27/39 Nx */
3779 /* Q.2971:Call-Control-N 22/39 N10 */
3780 unx_drop_party_ack(c, msg, u, 1);
3781 break;
3782
3783 default:
3784 /* Q.2971 10.5 4th paragraph */
3785 unx_drop_party_ack(c, msg, u, 0);
3786 break;
3787 }
3788 break;
3789
3790 case SIGC_COBISETUP: /* XXX */
3791 unx_unknown(c, msg, u);
3792 break;
3793
3794 /*
3795 * User signals
3796 */
3797 case SIGC_SETUP_request:
3798 if (c->cstate == CALLST_NULL) {
3799 /* Q.2971:Call-Control-U 4/39 (U0) */
3800 /* Q.2971:Call-Control-N 4/39 (N0) */
3801 if (c->uni->proto == UNIPROTO_UNI40N)
3802 un0_setup_request(c, msg, cookie, CALLST_N6);
3803 else
3804 un0_setup_request(c, msg, cookie, CALLST_U1);
3805 break;
3806 }
3807 VERBOSE(c->uni, UNI_FAC_ERR, 1, "setup.request in cs=%s",
3808 callstates[c->cstate].name);
3809 uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
3810 uni_msg_destroy(msg);
3811 break;
3812
3813 case SIGC_SETUP_response:
3814 if (c->cstate == CALLST_U6 || c->cstate == CALLST_U9 ||
3815 c->cstate == CALLST_U7) {
3816 /* Q.2971:Call-Control-U 13/39 (U6) */
3817 /* Q.2971:Call-Control-U 14/39 (U7) */
3818 /* Q.2971:Call-Control-U 17/39 (U9) */
3819 unx_setup_response(c, msg, cookie, CALLST_U8);
3820 break;
3821 }
3822 if (c->cstate == CALLST_N1 || c->cstate == CALLST_N3 ||
3823 c->cstate == CALLST_N4) {
3824 /* Q.2971:Call-Control-N 39/39 (N1) */
3825 /* Q.2971:Call-Control-N 7/39 (N3) */
3826 /* Q.2971:Call-Control-N 8/39 (N4) */
3827 unx_setup_response(c, msg, cookie, CALLST_N10);
3828 break;
3829 }
3830 VERBOSE(c->uni, UNI_FAC_ERR, 1, "setup.response in cs=%s",
3831 callstates[c->cstate].name);
3832 uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
3833 uni_msg_destroy(msg);
3834 break;
3835
3836 case SIGC_SETUP_COMPLETE_request:
3837 if (c->cstate == CALLST_N8) {
3838 /* Q.2971:Call-Control-N 15/39 (N8) */
3839 n8_setup_compl_request(c, msg, cookie, CALLST_N10);
3840 break;
3841 }
3842 VERBOSE(c->uni, UNI_FAC_ERR, 1, "setup_compl.request in cs=%s",
3843 callstates[c->cstate].name);
3844 uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
3845 uni_msg_destroy(msg);
3846 break;
3847
3848 case SIGC_PROCEEDING_request:
3849 if (c->cstate == CALLST_U6) {
3850 /* Q.2971:Call-Control-U 12/39 (U6) */
3851 u6n1_proceeding_request(c, msg, cookie, CALLST_U9);
3852 break;
3853 }
3854 if (c->cstate == CALLST_N1) {
3855 /* Q.2971:Call-Control-N 6/39 (N1) */
3856 u6n1_proceeding_request(c, msg, cookie, CALLST_N3);
3857 break;
3858 }
3859 VERBOSE(c->uni, UNI_FAC_ERR, 1, "proceeding.request in cs=%s",
3860 callstates[c->cstate].name);
3861 uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
3862 uni_msg_destroy(msg);
3863 break;
3864
3865 case SIGC_ALERTING_request:
3866 if (c->cstate == CALLST_U6 || c->cstate == CALLST_U9) {
3867 /* Q.2971:Call-Control-U 13/39 (U6) */
3868 /* Q.2971:Call-Control-U 17/39 (U9) */
3869 unx_alerting_request(c, msg, cookie, CALLST_U7);
3870 break;
3871 }
3872 if (c->cstate == CALLST_N1 || c->cstate == CALLST_N3) {
3873 /* Q.2971:Call-Control-N 38/39 (N1) */
3874 /* Q.2971:Call-Control-N 7/39 (N3) */
3875 unx_alerting_request(c, msg, cookie, CALLST_N4);
3876 break;
3877 }
3878 VERBOSE(c->uni, UNI_FAC_ERR, 1, "alerting.request in cs=%s",
3879 callstates[c->cstate].name);
3880 uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
3881 uni_msg_destroy(msg);
3882 break;
3883
3884 case SIGC_RELEASE_request:
3885 switch (c->cstate) {
3886
3887 case CALLST_U1:
3888 case CALLST_U3:
3889 case CALLST_U4:
3890 case CALLST_U6:
3891 case CALLST_U7:
3892 case CALLST_U8:
3893 case CALLST_U9:
3894 case CALLST_U10:
3895 /* Q.2971:Call-Control-U 27/39 */
3896 unx_release_request(c, msg, cookie, CALLST_U11);
3897 break;
3898
3899 case CALLST_N1:
3900 case CALLST_N3:
3901 case CALLST_N4:
3902 case CALLST_N6:
3903 case CALLST_N7:
3904 case CALLST_N8:
3905 case CALLST_N9:
3906 case CALLST_N10:
3907 /* Q.2971:Call-Control-N 28/39 */
3908 unx_release_request(c, msg, cookie, CALLST_N12);
3909 break;
3910
3911 case CALLST_U11:
3912 case CALLST_U12:
3913 case CALLST_N11:
3914 case CALLST_N12:
3915 case CALLST_NULL:
3916 VERBOSE(c->uni, UNI_FAC_ERR, 1,
3917 "release.request in cs=%s",
3918 callstates[c->cstate].name);
3919 uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE,
3920 cookie);
3921 uni_msg_destroy(msg);
3922 break;
3923 }
3924 break;
3925
3926 case SIGC_RELEASE_response:
3927 if (c->cstate == CALLST_U6 || c->cstate == CALLST_U12 ||
3928 c->cstate == CALLST_N1 || c->cstate == CALLST_N11) {
3929 /* Q.2971:Call-Control-U 12/39 (U6) */
3930 /* Q.2971:Call-Control-U 30/39 (U12) */
3931 /* Q.2971:Call-Control-N 6/39 (N1) */
3932 /* Q.2971:Call-Control-N 29/39 (N11) */
3933 unx_release_response(c, msg, cookie);
3934 break;
3935 }
3936 VERBOSE(c->uni, UNI_FAC_ERR, 1, "release.response in cs=%s",
3937 callstates[c->cstate].name);
3938 uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
3939 uni_msg_destroy(msg);
3940 break;
3941
3942 case SIGC_NOTIFY_request:
3943 /* Q.2971:Call-Control-U 18/39 */
3944 /* Q.2971:Call-Control-N 19/39 */
3945 unx_notify_request(c, msg, cookie);
3946 break;
3947
3948 case SIGC_STATUS_ENQUIRY_request:
3949 /* Q.2971:Call-Control-U 31/39 */
3950 /* Q.2971:Call-Control-N 32/39 */
3951 unx_status_enquiry_request(c, msg, cookie);
3952 break;
3953
3954 case SIGC_ADD_PARTY_request:
3955 if (c->cstate == CALLST_U4 || c->cstate == CALLST_U10 ||
3956 c->cstate == CALLST_N7 || c->cstate == CALLST_N10) {
3957 /* Q.2971:Call-Control-U 9-10/39 (U4) */
3958 /* Q.2971:Call-Control-U 21/39 (U10) */
3959 /* Q.2971:Call-Control-N 12/39 (N7) */
3960 /* Q.2971:Call-Control-N 22/39 (N10) */
3961 unx_add_party_request(c, msg, cookie);
3962 break;
3963 }
3964 VERBOSE(c->uni, UNI_FAC_ERR, 1, "add-party.request in cs=%s",
3965 callstates[c->cstate].name);
3966 uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
3967 uni_msg_destroy(msg);
3968 break;
3969
3970 case SIGC_PARTY_ALERTING_request:
3971 if (c->cstate == CALLST_U7 || c->cstate == CALLST_U8 ||
3972 c->cstate == CALLST_U10 ||
3973 c->cstate == CALLST_N4 || c->cstate == CALLST_N10) {
3974 /* Q.2971:Call-Control-U 14/39 U7 */
3975 /* Q.2971:Call-Control-U 15/39 U8 */
3976 /* Q.2971:Call-Control-U 21/39 U10 */
3977 /* Q.2971:Call-Control-N 8/39 N4 */
3978 /* Q.2971:Call-Control-N 22/39 N10 */
3979 unx_party_alerting_request(c, msg, cookie);
3980 break;
3981 }
3982 VERBOSE(c->uni, UNI_FAC_ERR, 1,
3983 "party-alerting.request in cs=%s",
3984 callstates[c->cstate].name);
3985 uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
3986 uni_msg_destroy(msg);
3987 break;
3988
3989 case SIGC_ADD_PARTY_ACK_request:
3990 if (c->cstate == CALLST_U10 || c->cstate == CALLST_N10) {
3991 /* Q.2971:Call-Control-U 21/39 (U10) */
3992 /* Q.2971:Call-Control-N 22/39 (N10)*/
3993 un10_add_party_ack_request(c, msg, cookie);
3994 break;
3995 }
3996 VERBOSE(c->uni, UNI_FAC_ERR, 1,
3997 "add-party-ack.request in cs=%s",
3998 callstates[c->cstate].name);
3999 uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
4000 uni_msg_destroy(msg);
4001 break;
4002
4003 case SIGC_ADD_PARTY_REJ_request:
4004 if (c->cstate == CALLST_U7 || c->cstate == CALLST_U8 ||
4005 c->cstate == CALLST_U10 ||
4006 c->cstate == CALLST_N4 || c->cstate == CALLST_N10) {
4007 /* Q.2971:Call-Control-U 14/39 U7 */
4008 /* Q.2971:Call-Control-U 15/39 U8 */
4009 /* Q.2971:Call-Control-U 21/39 U10 */
4010 /* Q.2971:Call-Control-N 8/39 N4 */
4011 /* Q.2971:Call-Control-N 22/39 N10 */
4012 unx_add_party_rej_request(c, msg, cookie);
4013 break;
4014 }
4015 VERBOSE(c->uni, UNI_FAC_ERR, 1,
4016 "add-party-rej.request in cs=%s",
4017 callstates[c->cstate].name);
4018 uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
4019 uni_msg_destroy(msg);
4020 break;
4021
4022 case SIGC_DROP_PARTY_request:
4023 if (c->cstate != CALLST_U11 && c->cstate != CALLST_U12 &&
4024 c->cstate != CALLST_N11 && c->cstate != CALLST_N12 &&
4025 c->cstate != CALLST_NULL) {
4026 /* Q.2971:Call-Control-U 21/39 U10 */
4027 /* Q.2971:Call-Control-U 26/39 U1-U9 */
4028 /* Q.2971:Call-Control-N 22/39 N10 */
4029 /* Q.2971:Call-Control-N 27/39 N1-N9 */
4030 unx_drop_party_request(c, msg, cookie);
4031 break;
4032 }
4033 VERBOSE(c->uni, UNI_FAC_ERR, 1, "drop-party.request in cs=%s",
4034 callstates[c->cstate].name);
4035 uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
4036 uni_msg_destroy(msg);
4037 break;
4038
4039 case SIGC_DROP_PARTY_ACK_request:
4040 if (c->cstate != CALLST_U11 && c->cstate != CALLST_U12 &&
4041 c->cstate != CALLST_N11 && c->cstate != CALLST_N12 &&
4042 c->cstate != CALLST_NULL) {
4043 /* Q.2971:Call-Control-U 21/39 U10 */
4044 /* Q.2971:Call-Control-U 26/39 U1-U9 */
4045 /* Q.2971:Call-Control-N 22/39 N10 */
4046 /* Q.2971:Call-Control-N 27/39 N1-N9 */
4047 unx_drop_party_ack_request(c, msg, cookie);
4048 break;
4049 }
4050 VERBOSE(c->uni, UNI_FAC_ERR, 1,
4051 "drop-party-ack.request in cs=%s",
4052 callstates[c->cstate].name);
4053 uniapi_call_error(c, UNIAPI_ERROR_BAD_CALLSTATE, cookie);
4054 uni_msg_destroy(msg);
4055 break;
4056
4057 case SIGC_ABORT_CALL_request:
4058 {
4059 struct uni *uni = c->uni;
4060
4061 uni_destroy_call(c, 0);
4062 uniapi_uni_error(uni, UNIAPI_OK, cookie, UNI_CALLSTATE_U0);
4063 break;
4064 }
4065
4066 /*
4067 * Timers
4068 */
4069 case SIGC_T301:
4070 if (c->cstate == CALLST_U4 || c->cstate == CALLST_N7) {
4071 /* Q.2971:Call-Control-U Missing */
4072 /* Q.2971:Call-Control-N 14/39 */
4073 u4n7_t301(c);
4074 break;
4075 }
4076 VERBOSE(c->uni, UNI_FAC_ERR, 1, "T301 in cs=%s",
4077 callstates[c->cstate].name);
4078 break;
4079
4080 case SIGC_T303:
4081 if (c->cstate == CALLST_U1 || c->cstate == CALLST_N6) {
4082 /* Q.2971:Call-Control-U 6/39 */
4083 /* Q.2971:Call-Control-N 11/39 */
4084 u1n6_t303(c);
4085 break;
4086 }
4087 VERBOSE(c->uni, UNI_FAC_ERR, 1, "T303 in cs=%s",
4088 callstates[c->cstate].name);
4089 break;
4090
4091 case SIGC_T308:
4092 if (c->cstate == CALLST_U11 || c->cstate == CALLST_N12) {
4093 /* Q.2971:Call-Control-U 28/39 */
4094 /* Q.2971:Call-Control-N 30/39 */
4095 u11n12_t308(c);
4096 break;
4097 }
4098 VERBOSE(c->uni, UNI_FAC_ERR, 1, "T308 in cs=%s",
4099 callstates[c->cstate].name);
4100 break;
4101
4102 case SIGC_T310:
4103 if (c->cstate == CALLST_U3 || c->cstate == CALLST_N9) {
4104 /* Q.2971:Call-Control-U 7/39 */
4105 /* Q.2971:Call-Control-N 17/39 */
4106 u3n9_t310(c);
4107 break;
4108 }
4109 VERBOSE(c->uni, UNI_FAC_ERR, 1, "T310 in cs=%s",
4110 callstates[c->cstate].name);
4111 break;
4112
4113 case SIGC_T313:
4114 if (c->cstate == CALLST_U8) {
4115 /* Q.2971:Call-Control-U 15/39 */
4116 u8_t313(c);
4117 break;
4118 }
4119 VERBOSE(c->uni, UNI_FAC_ERR, 1, "T313 in cs=%s",
4120 callstates[c->cstate].name);
4121 break;
4122
4123 case SIGC_T322:
4124 /* Q.2971:Call-Control-U 34/39 */
4125 /* Q.2971:Call-Control-N 35/39 */
4126 unx_t322(c);
4127 break;
4128
4129 case SIGC_CALL_DELETE:
4130 CALL_FREE(c);
4131 break;
4132
4133 /*
4134 * Party-Control
4135 */
4136 case SIGC_DROP_PARTY_indication:
4137 if (c->uni->proto == UNIPROTO_UNI40U)
4138 /* Q.2971:Call-Control-U 23/39 */
4139 ux_drop_party_indication(c, msg);
4140 else
4141 /* Q.2971:Call-Control-N 23/39 */
4142 nx_drop_party_indication(c, msg);
4143 break;
4144
4145 case SIGC_DROP_PARTY_ACK_indication:
4146 if (c->uni->proto == UNIPROTO_UNI40U)
4147 /* Q.2971:Call-Control-U 23/39 */
4148 ux_drop_party_ack_indication(c, msg);
4149 else
4150 /* Q.2971:Call-Control-N 23/39 */
4151 nx_drop_party_ack_indication(c, msg);
4152 break;
4153
4154 case SIGC_ADD_PARTY_REJ_indication:
4155 if (c->uni->proto == UNIPROTO_UNI40U)
4156 /* Q.2971:Call-Control-U 23/39 */
4157 ux_add_party_rej_indication(c, msg);
4158 else
4159 /* Q.2971:Call-Control-N 23/39 */
4160 nx_add_party_rej_indication(c, msg);
4161 break;
4162
4163
4164 case SIGC_SEND_DROP_PARTY:
4165 /* Q.2971:Call-Control-U 21/39 */
4166 /* Q.2971:Call-Control-U 25/39 */
4167 if (uni_party_act_count(c, 2) != 0)
4168 (void)uni_send_output(u, c->uni);
4169 else if(c->cstate != CALLST_U11) {
4170 c->uni->cause = u->u.drop_party.cause;
4171 clear_callD(c);
4172 }
4173 UNI_FREE(u);
4174 break;
4175
4176 case SIGC_SEND_DROP_PARTY_ACK:
4177 /* Q.2971:Call-Control-U 21/39 */
4178 /* Q.2971:Call-Control-U 25/39 */
4179 if (uni_party_act_count(c, 2) != 0)
4180 (void)uni_send_output(u, c->uni);
4181 else if (c->cstate != CALLST_U11) {
4182 c->uni->cause = u->u.drop_party_ack.cause;
4183 clear_callD(c);
4184 }
4185 UNI_FREE(u);
4186 break;
4187
4188 case SIGC_SEND_ADD_PARTY_REJ:
4189 /* Q.2971:Call-Control-U 21/39 */
4190 /* Q.2971:Call-Control-U 24/39 */
4191 unx_send_add_party_rej(c, u);
4192 break;
4193
4194 case SIGC_SEND_STATUS_ENQ:
4195 /* Q.2971:Call-Control-U 21/39 */
4196 /* Q.2971:Call-Control-U 25/39 */
4197 unx_send_party_status_enq(c, u);
4198 break;
4199
4200 case SIGC_PARTY_DESTROYED:
4201 c->uni->funcs->uni_output(c->uni, c->uni->arg,
4202 UNIAPI_PARTY_DESTROYED, cookie, msg);
4203 break;
4204
4205 case SIGC_END:
4206 break;
4207 }
4208
4209 return;
4210
4211 drop:
4212 /*
4213 * This is for SAAL message signals that should be dropped.
4214 */
4215 uni_msg_destroy(msg);
4216 UNI_FREE(u);
4217 }
4218
4219 /**********************************************************************/
4220
4221 /*
4222 * Timeout functions
4223 */
4224 static void
4225 t308_func(struct call *c)
4226 {
4227 uni_enq_call(c, SIGC_T308, 0, NULL, NULL);
4228 }
4229 static void
4230 t303_func(struct call *c)
4231 {
4232 uni_enq_call(c, SIGC_T303, 0, NULL, NULL);
4233 }
4234 static void
4235 t301_func(struct call *c)
4236 {
4237 uni_enq_call(c, SIGC_T301, 0, NULL, NULL);
4238 }
4239 static void
4240 t310_func(struct call *c)
4241 {
4242 uni_enq_call(c, SIGC_T310, 0, NULL, NULL);
4243 }
4244 static void
4245 t313_func(struct call *c)
4246 {
4247 uni_enq_call(c, SIGC_T313, 0, NULL, NULL);
4248 }
4249
4250 static void
4251 t322_func(struct call *c)
4252 {
4253 uni_enq_call(c, SIGC_T322, 0, NULL, NULL);
4254 }
4255
4256 /**********************************************************************/
4257
4258 /*
4259 * Check whether the peer state is compatible with our state.
4260 * Return the new callstate we should go to (either U0 or the current
4261 * state).
4262 * None of the state is U0 here. My state is not U11 or U12.
4263 *
4264 * Well, this turns out to be not so easy: the status enquiry could have
4265 * been sent before we changed into the current state - the status will
4266 * report a previous state without anything been lost.
4267 *
4268 * Incoming states are incompatible with outgoing states. Everything is ok.
4269 */
4270 static enum call_state
4271 state_compat(struct call *c, enum uni_callstate peer)
4272 {
4273 if ((c->cstate == CALLST_U1 ||
4274 c->cstate == CALLST_U3 ||
4275 c->cstate == CALLST_U4) &&
4276 (peer == UNI_CALLSTATE_N6 ||
4277 peer == UNI_CALLSTATE_N7 ||
4278 peer == UNI_CALLSTATE_N8 ||
4279 peer == UNI_CALLSTATE_N9))
4280 return (CALLST_NULL);
4281
4282 if ((c->cstate == CALLST_N6 ||
4283 c->cstate == CALLST_N7 ||
4284 c->cstate == CALLST_N8 ||
4285 c->cstate == CALLST_N9) &&
4286 (peer == UNI_CALLSTATE_U1 ||
4287 peer == UNI_CALLSTATE_U3 ||
4288 peer == UNI_CALLSTATE_U4))
4289 return (CALLST_NULL);
4290
4291 if ((peer == UNI_CALLSTATE_N1 ||
4292 peer == UNI_CALLSTATE_N3 ||
4293 peer == UNI_CALLSTATE_N4) &&
4294 (c->cstate == CALLST_U6 ||
4295 c->cstate == CALLST_U7 ||
4296 c->cstate == CALLST_U8 ||
4297 c->cstate == CALLST_N9))
4298 return (CALLST_NULL);
4299
4300 if ((peer == UNI_CALLSTATE_U6 ||
4301 peer == UNI_CALLSTATE_U7 ||
4302 peer == UNI_CALLSTATE_U8 ||
4303 peer == UNI_CALLSTATE_U9) &&
4304 (c->cstate == CALLST_N1 ||
4305 c->cstate == CALLST_N3 ||
4306 c->cstate == CALLST_N4))
4307 return (CALLST_NULL);
4308
4309 return (c->cstate);
4310 }
Cache object: f85b48d2b94f963e6d5c5e792e47693f
|