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 50static enum call_state state_compat(struct call *, enum uni_callstate); 51static 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, 55static const char *const call_sigs[] = { 56 DEF_CALL_SIGS 57}; 58#undef DEF_PRIV_SIG 59 60TIMER_FUNC_CALL(t308, t308_func) 61TIMER_FUNC_CALL(t303, t303_func) 62TIMER_FUNC_CALL(t301, t301_func) 63TIMER_FUNC_CALL(t310, t310_func) 64TIMER_FUNC_CALL(t313, t313_func) 65TIMER_FUNC_CALL(t322, t322_func) 66 67const 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 91static void unx_send_add_party_rej(struct call *c, struct uni_all *u); 92 93static __inline void 94set_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 111static enum uni_callstate 112map_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 */ 122struct call * 123uni_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} 132struct call * 133uni_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 */ 146struct call * 147uni_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 187struct call * 188uni_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 */ 212void 213uni_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 253static void 254allocate_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 277static void 278reset_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 */ 303static void 304clear_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 */ 359static void 360un0_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 */ 468static void 469un0_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 */ 546static void 547u1n6_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 */ 639static void 640u1n6_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 */ 690static void 691u3n9_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 */ 706static void 707u4n7_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 */ 730static void 731unx_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 */ 831static void 832u6n1_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 */ 868static void 869unx_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 */ 917static void 918unx_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 */ 982static void 983n8_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 */ 1027static void 1028unx_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 */ 1159static void 1160u8_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 */ 1175static void 1176u8_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 */ 1251static void 1252n10_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 */ 1292static void 1293unx_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 */ 1333void 1334uni_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} 1368static void 1369unx_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 */ 1387static void 1388unx_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 */ 1440static void 1441u11n12_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 */ 1475static void 1476unx_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 */ 1547static void 1548unx_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 */ 1578static void 1579unx_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 */ 1626static void 1627respond_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 */ 1648static void 1649u11n12_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 */ 1701static void 1702un11un12_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 1791static int 1792status_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 */ 1805static void 1806unx_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 */ 1945static void 1946unx_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 */ 1995static void 1996unx_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 */ 2027static void 2028unx_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 */ 2090static void 2091un10_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 */ 2111static void 2112unx_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 */ 2142static void 2143un10_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 */ 2173static void 2174call_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 */ 2199static void 2200un10_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 */ 2224static void 2225unx_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 */ 2236static void 2237un10_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 */ 2257static void 2258unx_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 2276static void 2277make_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 */ 2301static void 2302ux_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 */ 2324static void 2325nx_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 */ 2353static void 2354ux_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 */ 2376static void 2377nx_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 */ 2405static void 2406ux_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 */ 2428static void 2429nx_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 */ 2460static void 2461unx_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 */ 2506static void 2507un10_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 */ 2541static void 2542unx_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 */ 2576static void 2577unx_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 */ 2610static void 2611unx_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 */ 2639static void 2640unx_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 */ 2673static void 2674unx_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 */ 2796static void 2797un10n8_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 */ 2874static void 2875default_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 */ 2896static void 2897unx_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 */ 2978static void 2979handle_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 */ 3005static void 3006unx_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 */ 3028static void 3029unx_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 */ 3101static void 3102unx_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 */ 3184static void 3185unx_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 */ 3252void 3253uni_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 */ 3309static void 3310unx_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 3333void 3334uni_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 */ 4224static void 4225t308_func(struct call *c) 4226{ 4227 uni_enq_call(c, SIGC_T308, 0, NULL, NULL); 4228} 4229static void 4230t303_func(struct call *c) 4231{ 4232 uni_enq_call(c, SIGC_T303, 0, NULL, NULL); 4233} 4234static void 4235t301_func(struct call *c) 4236{ 4237 uni_enq_call(c, SIGC_T301, 0, NULL, NULL); 4238} 4239static void 4240t310_func(struct call *c) 4241{ 4242 uni_enq_call(c, SIGC_T310, 0, NULL, NULL); 4243} 4244static void 4245t313_func(struct call *c) 4246{ 4247 uni_enq_call(c, SIGC_T313, 0, NULL, NULL); 4248} 4249 4250static void 4251t322_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 */ 4270static enum call_state 4271state_compat(struct call *c, enum uni_callstate peer) 4272{ 4273 if ((c->cstate == CALLST_U1 || 4274 c->cstate == CALLST_U3 || 4275 c->cstate == CALLST_U4) && 4276 (peer == UNI_CALLSTATE_N6 || 4277 peer == UNI_CALLSTATE_N7 || 4278 peer == UNI_CALLSTATE_N8 || 4279 peer == UNI_CALLSTATE_N9)) 4280 return (CALLST_NULL); 4281 4282 if ((c->cstate == CALLST_N6 || 4283 c->cstate == CALLST_N7 || 4284 c->cstate == CALLST_N8 || 4285 c->cstate == CALLST_N9) && 4286 (peer == UNI_CALLSTATE_U1 || 4287 peer == UNI_CALLSTATE_U3 || 4288 peer == UNI_CALLSTATE_U4)) 4289 return (CALLST_NULL); 4290 4291 if ((peer == UNI_CALLSTATE_N1 || 4292 peer == UNI_CALLSTATE_N3 || 4293 peer == UNI_CALLSTATE_N4) && 4294 (c->cstate == CALLST_U6 || 4295 c->cstate == CALLST_U7 || 4296 c->cstate == CALLST_U8 || 4297 c->cstate == CALLST_N9)) 4298 return (CALLST_NULL); 4299 4300 if ((peer == UNI_CALLSTATE_U6 || 4301 peer == UNI_CALLSTATE_U7 || 4302 peer == UNI_CALLSTATE_U8 || 4303 peer == UNI_CALLSTATE_U9) && 4304 (c->cstate == CALLST_N1 || 4305 c->cstate == CALLST_N3 || 4306 c->cstate == CALLST_N4)) 4307 return (CALLST_NULL); 4308 4309 return (c->cstate); 4310} 4311