1/* 2 * Copyright (c) 1996-2003 3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4 * All rights reserved. 5 * 6 * Author: Hartmut Brandt <harti@freebsd.org> 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $Begemot: libunimsg/netnatm/sig/sig_reset.c,v 1.11 2004/08/05 07:11:03 brandt Exp $ 30 * 31 * Reset-start and reset-respond 32 */ 33 34#include <netnatm/unimsg.h> 35#include <netnatm/saal/sscfudef.h> 36#include <netnatm/msg/unistruct.h> 37#include <netnatm/msg/unimsglib.h> 38#include <netnatm/sig/uni.h> 39 40#include <netnatm/sig/unipriv.h> 41#include <netnatm/sig/unimkmsg.h> 42 43static void response_restart(struct uni *, struct uni_msg *, struct uni_all *); 44static void response_status(struct uni *, struct uni_msg *, struct uni_all *); 45 46static void response_t317(struct uni *); 47 48static void response_error(struct uni *, struct uniapi_reset_error_response *, 49 uint32_t cookie); 50static void response_response(struct uni *, struct uniapi_reset_response *, 51 uint32_t); 52 53static void start_request(struct uni *, struct uniapi_reset_request *, 54 uint32_t); 55 56static void start_t316(struct uni *); 57 58static void start_restart_ack(struct uni *, struct uni_msg *, struct uni_all *); 59static void start_status(struct uni *, struct uni_msg *, struct uni_all *); 60 61static int restart_forward(struct uni *, const struct uni_all *); 62 63#define DEF_PRIV_SIG(NAME, FROM) [SIG##NAME] = "SIG"#NAME, 64static const char *const start_sigs[] = { 65 DEF_START_SIGS 66}; 67#undef DEF_PRIV_SIG 68 69#define DEF_PRIV_SIG(NAME, FROM) [SIG##NAME] = "SIG"#NAME, 70static const char *const respond_sigs[] = { 71 DEF_RESPOND_SIGS 72}; 73#undef DEF_PRIV_SIG 74 75TIMER_FUNC_UNI(t317, t317_func) 76TIMER_FUNC_UNI(t316, t316_func) 77 78/* 79 * Reset-Start process. 80 */ 81void 82uni_sig_start(struct uni *uni, u_int sig, uint32_t cookie, 83 struct uni_msg *m, struct uni_all *u) 84{ 85 if (sig >= SIGS_END) { 86 VERBOSE(uni, UNI_FAC_ERR, 1, "Signal %d outside of range to " 87 "Reset-Start", sig); 88 if (m) 89 uni_msg_destroy(m); 90 if (u) 91 UNI_FREE(u); 92 return; 93 } 94 95 VERBOSE(uni, UNI_FAC_RESTART, 1, 96 "Signal %s in state %u of Reset-Start; cookie %u", 97 start_sigs[sig], uni->glob_start, cookie); 98 99 switch (sig) { 100 101 /* 102 * User requests 103 */ 104 case SIGS_RESET_request: 105 start_request(uni, 106 uni_msg_rptr(m, struct uniapi_reset_request *), cookie); 107 uni_msg_destroy(m); 108 break; 109 110 /* 111 * Timers 112 */ 113 case SIGS_T316: 114 start_t316(uni); 115 break; 116 117 /* 118 * SAAL 119 */ 120 case SIGS_RESTART_ACK: 121 start_restart_ack(uni, m, u); 122 uni_msg_destroy(m); 123 UNI_FREE(u); 124 break; 125 126 case SIGS_STATUS: 127 start_status(uni, m, u); 128 uni_msg_destroy(m); 129 UNI_FREE(u); 130 break; 131 132 case SIGS_END: 133 break; 134 } 135} 136 137/* 138 * Reset-request from USER. 139 * 140 * Q.2931:Reset-Start 1/2 141 */ 142static void 143start_request(struct uni *uni, struct uniapi_reset_request *req, uint32_t cookie) 144{ 145 struct uni_all *resp; 146 int err; 147 148 if (uni->glob_start != UNI_CALLSTATE_REST0) { 149 uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0); 150 return; 151 } 152 153 if ((resp = UNI_ALLOC()) == NULL) { 154 uniapi_uni_error(uni, UNIAPI_ERROR_NOMEM, cookie, 0); 155 return; 156 } 157 158 MK_MSG_ORIG(resp, UNI_RESTART, 0, 0); 159 resp->u.restart.restart = req->restart; 160 resp->u.restart.connid = req->connid; 161 162 if (restart_forward(uni, resp)) 163 return; 164 165 uni->connid_start = req->connid; 166 uni->restart_start = req->restart; 167 168 if ((err = uni_send_output(resp, uni)) != 0) 169 uniapi_uni_error(uni, UNIAPI_ERROR_ENCODING, cookie, 0); 170 UNI_FREE(resp); 171 if (err) 172 return; 173 174 uni->cnt316 = 0; 175 TIMER_START_UNI(uni, t316, uni->timer316); 176 uni->glob_start = UNI_CALLSTATE_REST1; 177 178 VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 1"); 179 180 181 uniapi_uni_error(uni, UNIAPI_OK, cookie, 0); 182} 183 184/* 185 * T316 timeout function 186 */ 187static void 188t316_func(struct uni *uni) 189{ 190 uni_enq_start(uni, SIGS_T316, 0, NULL, NULL); 191} 192 193/* 194 * Q.2931:Reset-Start 1/2 195 */ 196static void 197start_t316(struct uni *uni) 198{ 199 if (uni->glob_start != UNI_CALLSTATE_REST1) { 200 VERBOSE0(uni, UNI_FAC_ERR, "T316 in state %d", 201 uni->glob_start); 202 return; 203 } 204 205 if (++uni->cnt316 == uni->init316) { 206 struct uni_msg *app; 207 struct uniapi_reset_error_indication *resp; 208 209 VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start error"); 210 211 resp = ALLOC_API(struct uniapi_reset_error_indication, app); 212 if (resp != NULL) { 213 resp->source = 0; 214 resp->reason = UNIAPI_RESET_ERROR_NO_RESPONSE, 215 216 uni->funcs->uni_output(uni, uni->arg, 217 UNIAPI_RESET_ERROR_indication, 0, app); 218 } 219 220 uni->glob_start = UNI_CALLSTATE_REST0; 221 VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 0"); 222 } else { 223 struct uni_all *resp; 224 225 if ((resp = UNI_ALLOC()) == NULL) 226 return; 227 228 MK_MSG_ORIG(resp, UNI_RESTART, 0, 0); 229 resp->u.restart.restart = uni->restart_start; 230 resp->u.restart.connid = uni->connid_start; 231 232 (void)uni_send_output(resp, uni); 233 234 UNI_FREE(resp); 235 236 TIMER_START_UNI(uni, t316, uni->timer316); 237 } 238} 239 240/* 241 * Got RESTART_ACK. 242 */ 243static void 244start_restart_ack(struct uni *uni, struct uni_msg *m, struct uni_all *u) 245{ 246 enum uni_callstate new_state; 247 struct uniapi_reset_confirm *conf; 248 struct uni_msg *app; 249 250 if (uni->glob_start == UNI_CALLSTATE_REST0) { 251 uni_respond_status_mtype(uni, &u->u.hdr.cref, uni->glob_start, 252 UNI_CAUSE_MSG_INCOMP, UNI_RESTART_ACK); 253 return; 254 } 255 256 if (uni->glob_start != UNI_CALLSTATE_REST1) { 257 ASSERT(0, ("bad global call state in Reset-Start")); 258 return; 259 } 260 261 /* 262 * If body decoding fails, this is because IEs are wrong. 263 */ 264 (void)uni_decode_body(m, u, &uni->cx); 265 MANDATE_IE(uni, u->u.restart_ack.restart, UNI_IE_RESTART); 266 267 if (IE_ISGOOD(u->u.restart_ack.restart)) { 268 /* 269 * Q.2931: 5.5.2.2 270 */ 271 if (u->u.restart_ack.restart.rclass == UNI_RESTART_ALL && 272 IE_ISGOOD(u->u.restart_ack.connid)) { 273 (void)UNI_SAVE_IERR(&uni->cx, UNI_IE_CONNID, 274 u->u.restart_ack.connid.h.act, 275 UNI_IERR_UNK); 276 } else if ((u->u.restart_ack.restart.rclass == UNI_RESTART_PATH || 277 u->u.restart_ack.restart.rclass == UNI_RESTART_CHANNEL)) { 278 MANDATE_IE(uni, u->u.restart_ack.connid, UNI_IE_CONNID); 279 } 280 } 281 /* 282 * Compare the information elements now, because 283 * we may need the new callstate for the status message 284 * below. 285 */ 286 new_state = UNI_CALLSTATE_REST1; 287 288 if (IE_ISGOOD(u->u.restart_ack.restart) && 289 IE_ISGOOD(uni->restart_start) && 290 u->u.restart_ack.restart.rclass == uni->restart_start.rclass && 291 !IE_ISGOOD(u->u.restart_ack.connid) == !IE_ISGOOD(uni->connid_start) && 292 (!IE_ISGOOD(uni->connid_start) || 293 (u->u.restart_ack.connid.vpci == uni->connid_start.vpci && 294 u->u.restart_ack.connid.vci == uni->connid_start.vci))) 295 new_state = UNI_CALLSTATE_REST0; 296 297 switch (uni_verify(uni, u->u.hdr.act)) { 298 case VFY_RAIM: 299 case VFY_RAI: 300 uni_respond_status_verify(uni, &u->u.hdr.cref, 301 UNI_CALLSTATE_REST1, NULL, 0); 302 case VFY_I: 303 return; 304 305 case VFY_CLR: 306 uni->glob_start = UNI_CALLSTATE_REST0; 307 VERBOSE(uni, UNI_FAC_RESTART, 1, 308 "Reset-Start state := 0"); 309 return; 310 311 case VFY_RAP: 312 case VFY_RAPU: 313 uni_respond_status_verify(uni, &u->u.hdr.cref, 314 new_state, NULL, 0); 315 case VFY_OK: 316 break; 317 } 318 319 if (new_state == UNI_CALLSTATE_REST1) 320 /* 321 * Q.2931: 5.5.1.2/2 322 */ 323 return; 324 325 /* 326 * Build restart.confirm signal for application 327 */ 328 if (!IE_ISGOOD(u->u.restart_ack.connid)) 329 u->u.restart.connid.h.present = 0; 330 331 332 if ((conf = ALLOC_API(struct uniapi_reset_confirm, app)) == NULL) 333 return; 334 conf->restart = u->u.restart.restart; 335 conf->connid = u->u.restart.connid; 336 337 TIMER_STOP_UNI(uni, t316); 338 339 uni->funcs->uni_output(uni, uni->arg, UNIAPI_RESET_confirm, 0, app); 340 341 uni->glob_start = UNI_CALLSTATE_REST0; 342 VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 0"); 343} 344 345/* 346 * Reset-Start got a STATUS message. 347 * 348 * Q.2931: Reset-Start 2/2 349 * 350 * In Q.2931 only CALLSTATE_REST1 is allowed, this seems silly and to contradict 351 * 5.6.12. So allow it in any state. 352 * 353 * The following states are considered compatible: 354 * 355 * Sender Receiver(we) 356 * ------ -------- 357 * Rest0 Rest0 this is the normal state OK! 358 * Rest2 Rest0 this may be the result of no answer from the API 359 * on the remote end and the us finally timing out. ERROR! 360 * Rest2 Rest1 this is normal. OK! 361 * Rest0 Rest1 RESTART_ACK was probably lost. OK! 362 * 363 * All others are wrong. 364 */ 365static void 366start_status(struct uni *uni, struct uni_msg *m, struct uni_all *u) 367{ 368 (void)uni_decode_body(m, u, &uni->cx); 369 MANDATE_IE(uni, u->u.status.callstate, UNI_IE_CALLSTATE); 370 MANDATE_IE(uni, u->u.status.cause, UNI_IE_CAUSE); 371 switch (uni_verify(uni, u->u.hdr.act)) { 372 case VFY_CLR: 373 uni->glob_start = UNI_CALLSTATE_REST0; 374 VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 0"); 375 return; 376 377 case VFY_RAIM: 378 case VFY_RAI: 379 case VFY_RAP: 380 case VFY_RAPU: 381 uni_respond_status_verify(uni, &u->u.hdr.cref, uni->glob_start, 382 NULL, 0); 383 case VFY_I: 384 case VFY_OK: 385 break; 386 } 387 if (!IE_ISGOOD(u->u.status.callstate)) { 388 /* 389 * As a result of the strange handling above, we must 390 * process a STATUS with an invalid or missing callstate! 391 */ 392 return; 393 } 394 if ((u->u.status.callstate.state == UNI_CALLSTATE_REST0 && 395 uni->glob_start == UNI_CALLSTATE_REST0) || 396 (u->u.status.callstate.state == UNI_CALLSTATE_REST0 && 397 uni->glob_start == UNI_CALLSTATE_REST1) || 398 (u->u.status.callstate.state == UNI_CALLSTATE_REST2 && 399 uni->glob_start == UNI_CALLSTATE_REST1)) { 400 /* 401 * Implementation dependend procedure: 402 * Inform the API 403 */ 404 struct uniapi_reset_status_indication *resp; 405 struct uni_msg *app; 406 407 resp = ALLOC_API(struct uniapi_reset_status_indication, app); 408 if (resp == NULL) 409 return; 410 resp->cref = u->u.hdr.cref; 411 resp->callstate = u->u.status.callstate; 412 if (IE_ISGOOD(u->u.status.cause)) 413 resp->cause = u->u.status.cause; 414 415 uni->funcs->uni_output(uni, uni->arg, 416 UNIAPI_RESET_STATUS_indication, 0, app); 417 418 } else { 419 struct uniapi_reset_error_indication *resp; 420 struct uni_msg *app; 421 422 resp = ALLOC_API(struct uniapi_reset_error_indication, app); 423 if (resp != NULL) { 424 resp->source = 0; 425 resp->reason = UNIAPI_RESET_ERROR_PEER_INCOMP_STATE, 426 427 uni->funcs->uni_output(uni, uni->arg, 428 UNIAPI_RESET_ERROR_indication, 0, app); 429 } 430 } 431} 432 433/************************************************************/ 434/* 435 * Reset-Respond process. 436 */ 437void 438uni_sig_respond(struct uni *uni, u_int sig, uint32_t cookie, 439 struct uni_msg *m, struct uni_all *u) 440{ 441 if (sig >= SIGR_END) { 442 VERBOSE(uni, UNI_FAC_ERR, 1, "Signal %d outside of range to " 443 "Reset-Respond", sig); 444 if (m) 445 uni_msg_destroy(m); 446 if (u) 447 UNI_FREE(u); 448 return; 449 } 450 451 VERBOSE(uni, UNI_FAC_RESTART, 1, 452 "Signal %s in state %u of Reset-Respond; cookie %u", 453 respond_sigs[sig], uni->glob_respond, cookie); 454 455 switch (sig) { 456 457 /* 458 * SAAL 459 */ 460 case SIGR_RESTART: 461 response_restart(uni, m, u); 462 uni_msg_destroy(m); 463 UNI_FREE(u); 464 break; 465 466 case SIGR_STATUS: 467 response_status(uni, m, u); 468 uni_msg_destroy(m); 469 UNI_FREE(u); 470 break; 471 472 /* 473 * User 474 */ 475 case SIGR_RESET_ERROR_response: 476 response_error(uni, 477 uni_msg_rptr(m, struct uniapi_reset_error_response *), 478 cookie); 479 uni_msg_destroy(m); 480 break; 481 482 case SIGR_RESET_response: 483 response_response(uni, 484 uni_msg_rptr(m, struct uniapi_reset_response *), cookie); 485 uni_msg_destroy(m); 486 break; 487 488 /* 489 * Timers 490 */ 491 case SIGR_T317: 492 response_t317(uni); 493 return; 494 495 case SIGR_END: 496 break; 497 } 498} 499 500/* 501 * Send a RELEASE_COMPLETE to all affected calls as per 502 * F.2.3(3) 503 */ 504static int 505restart_forward(struct uni *uni, const struct uni_all *u) 506{ 507 struct call *c; 508 struct uni_all *resp; 509 510 if ((resp = UNI_ALLOC()) == NULL) 511 return (-1); 512 513 TAILQ_FOREACH(c, &uni->calls, link) { 514 if (u->u.restart.restart.rclass == UNI_RESTART_ALL || 515 (IE_ISPRESENT(c->connid) && 516 u->u.restart.connid.vpci == c->connid.vpci && 517 (u->u.restart.restart.rclass == UNI_RESTART_PATH || 518 u->u.restart.connid.vci == c->connid.vci))) { 519 MK_MSG_ORIG(resp, UNI_RELEASE_COMPL, c->cref, c->mine); 520 uni_release_compl(c, resp); 521 } 522 } 523 524 UNI_FREE(resp); 525 return (0); 526} 527 528/* 529 * Respond process got a restart message. 530 * Doesn't free the messages. 531 */ 532static void 533response_restart(struct uni *uni, struct uni_msg *m, struct uni_all *u) 534{ 535 struct uni_msg *app; 536 struct uniapi_reset_indication *ind; 537 538 if (uni->glob_respond == UNI_CALLSTATE_REST0) { 539 /* 540 * If body decoding fails, this is because IEs are wrong. 541 */ 542 (void)uni_decode_body(m, u, &uni->cx); 543 MANDATE_IE(uni, u->u.restart.restart, UNI_IE_RESTART); 544 if (IE_ISGOOD(u->u.restart.restart)) { 545 /* 546 * Q.2931: 5.5.2.2 547 */ 548 if (u->u.restart.restart.rclass == UNI_RESTART_ALL && 549 IE_ISGOOD(u->u.restart.connid)) { 550 (void)UNI_SAVE_IERR(&uni->cx, UNI_IE_CONNID, 551 u->u.restart.connid.h.act, 552 UNI_IERR_UNK); 553 } else if ((u->u.restart.restart.rclass == UNI_RESTART_PATH || 554 u->u.restart.restart.rclass == UNI_RESTART_CHANNEL)) { 555 MANDATE_IE(uni, u->u.restart.connid, UNI_IE_CONNID); 556 } 557 } 558 switch (uni_verify(uni, u->u.hdr.act)) { 559 case VFY_RAIM: 560 case VFY_RAI: 561 uni_respond_status_verify(uni, &u->u.hdr.cref, 562 UNI_CALLSTATE_REST0, NULL, 0); 563 case VFY_CLR: 564 case VFY_I: 565 return; 566 567 case VFY_RAP: 568 case VFY_RAPU: 569 uni_respond_status_verify(uni, &u->u.hdr.cref, 570 UNI_CALLSTATE_REST2, NULL, 0); 571 case VFY_OK: 572 break; 573 } 574 if (!IE_ISGOOD(u->u.restart.connid)) 575 u->u.restart.connid.h.present = 0; 576 577 /* 578 * Send a RELEASE_COMPLETE to all affected calls as per 579 * F.2.3(3) 580 */ 581 if (restart_forward(uni, u)) 582 return; 583 584 /* 585 * Build restart signal for application 586 */ 587 if ((ind = ALLOC_API(struct uniapi_reset_indication, app)) == NULL) 588 return; 589 590 ind->restart = u->u.restart.restart; 591 ind->connid = u->u.restart.connid; 592 593 uni_enq_coord(uni, SIGO_RESET_indication, 0, app); 594 595 TIMER_START_UNI(uni, t317, uni->timer317); 596 uni->glob_respond = UNI_CALLSTATE_REST2; 597 598 VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond state := 2"); 599 600 601 } else if (uni->glob_respond == UNI_CALLSTATE_REST2) { 602 /* 603 * No need to decode the message. It is unexpected in this 604 * state so return a status. 605 */ 606 uni_respond_status_mtype(uni, &u->u.hdr.cref, uni->glob_respond, 607 UNI_CAUSE_MSG_INCOMP, UNI_RESTART); 608 609 610 } else 611 ASSERT(0, ("bad global call state in responder")); 612} 613 614static void 615response_t317(struct uni *uni) 616{ 617 struct uniapi_reset_error_indication *resp; 618 struct uni_msg *app; 619 620 if (uni->glob_respond != UNI_CALLSTATE_REST2) { 621 VERBOSE0(uni, UNI_FAC_ERR, "T317 in state %d", 622 uni->glob_respond); 623 return; 624 } 625 626 VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond error"); 627 628 if ((resp = ALLOC_API(struct uniapi_reset_error_indication, app)) != NULL) { 629 resp->source = 1; 630 resp->reason = UNIAPI_RESET_ERROR_NO_CONFIRM; 631 632 uni->funcs->uni_output(uni, uni->arg, 633 UNIAPI_RESET_ERROR_indication, 0, app); 634 } 635 636 uni->glob_respond = UNI_CALLSTATE_REST0; 637 VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond state := 0"); 638} 639 640/* 641 * Error response from USER 642 */ 643static void 644response_error(struct uni *uni, struct uniapi_reset_error_response *c, 645 uint32_t cookie) 646{ 647 struct uni_all *resp; 648 649 if (uni->glob_respond != UNI_CALLSTATE_REST2) { 650 uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0); 651 return; 652 } 653 654 if ((resp = UNI_ALLOC()) == NULL) { 655 uniapi_uni_error(uni, UNIAPI_ERROR_NOMEM, cookie, 0); 656 return; 657 } 658 659 MK_MSG_ORIG(resp, UNI_STATUS, 0, 1); 660 MK_IE_CALLSTATE(resp->u.status.callstate, UNI_CALLSTATE_REST2); 661 662 if (IE_ISGOOD(c->cause)) 663 resp->u.status.cause = c->cause; 664 else { 665 MK_IE_CAUSE(resp->u.status.cause, UNI_CAUSE_LOC_USER, 666 UNI_CAUSE_CHANNEL_NEX); 667 if (IE_ISGOOD(uni->connid_respond)) 668 ADD_CAUSE_CHANNID(resp->u.status.cause, 669 uni->connid_respond.vpci, 670 uni->connid_respond.vci); 671 } 672 673 if (uni_send_output(resp, uni) != 0) { 674 uniapi_uni_error(uni, UNIAPI_ERROR_ENCODING, cookie, 0); 675 UNI_FREE(resp); 676 return; 677 } 678 679 uniapi_uni_error(uni, UNIAPI_OK, cookie, 0); 680} 681 682/* 683 * Reset-response from user. 684 */ 685static void 686response_response(struct uni *uni, struct uniapi_reset_response *arg, 687 uint32_t cookie) 688{ 689 struct uni_all *resp; 690 691 if (uni->glob_respond != UNI_CALLSTATE_REST2) { 692 uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0); 693 return; 694 } 695 696 if (!IE_ISGOOD(arg->restart)) { 697 uniapi_uni_error(uni, UNIAPI_ERROR_MISSING_IE, cookie, 0); 698 return; 699 } 700 701 if ((resp = UNI_ALLOC()) == NULL) { 702 uniapi_uni_error(uni, UNIAPI_ERROR_NOMEM, cookie, 0); 703 return; 704 } 705 706 TIMER_STOP_UNI(uni, t317); 707 708 MK_MSG_ORIG(resp, UNI_RESTART_ACK, 0, 1); 709 resp->u.restart.restart = arg->restart; 710 if (IE_ISGOOD(arg->connid)) 711 resp->u.restart.connid = arg->connid; 712 713 if (uni_send_output(resp, uni) != 0) { 714 uniapi_uni_error(uni, UNIAPI_ERROR_ENCODING, cookie, 0); 715 UNI_FREE(resp); 716 return; 717 } 718 719 UNI_FREE(resp); 720 721 uni->glob_respond = UNI_CALLSTATE_REST0; 722 VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond state := 0"); 723 724 uniapi_uni_error(uni, UNIAPI_OK, cookie, 0); 725} 726 727/* 728 * Reset-Response got a STATUS message. 729 * 730 * Q.2931: Reset-Response 2/2 731 * 732 * In Q.2931 only CALLSTATE_REST2 is allowed, this seems silly and to contradict 733 * 5.6.12. So allow it in any state. 734 * 735 * The following states are considered compatible: 736 * 737 * Sender Receiver 738 * ------ -------- 739 * Rest0 Rest0 this is the normal state OK! 740 * Rest0 Rest2 this may be the result of no answer from the API 741 * and the Sender finally timing out. ERROR! 742 * Rest1 Rest2 this is normal. OK! 743 * Rest1 Rest0 RESTART_ACK was probably lost. OK! 744 * 745 * All others are wrong. 746 */ 747static void 748response_status(struct uni *uni, struct uni_msg *m, struct uni_all *u) 749{ 750 (void)uni_decode_body(m, u, &uni->cx); 751 MANDATE_IE(uni, u->u.status.callstate, UNI_IE_CALLSTATE); 752 MANDATE_IE(uni, u->u.status.cause, UNI_IE_CAUSE); 753 switch (uni_verify(uni, u->u.hdr.act)) { 754 case VFY_CLR: 755 if (uni->proto == UNIPROTO_UNI40U) { 756 uni->glob_respond = UNI_CALLSTATE_REST0; 757 VERBOSE(uni, UNI_FAC_RESTART, 1, 758 "Reset-Respond state := 0"); 759 return; 760 } 761 break; 762 763 case VFY_RAIM: 764 case VFY_RAI: 765 case VFY_RAP: 766 case VFY_RAPU: 767 uni_respond_status_verify(uni, &u->u.hdr.cref, 768 uni->glob_respond, NULL, 0); 769 case VFY_I: 770 case VFY_OK: 771 break; 772 } 773 if (!IE_ISGOOD(u->u.status.callstate)) { 774 /* 775 * As a result of the strange handling above, we must 776 * process a STATUS with an invalid or missing callstate! 777 */ 778 return; 779 } 780 if ((u->u.status.callstate.state == UNI_CALLSTATE_REST0 && 781 uni->glob_respond == UNI_CALLSTATE_REST0) || 782 (u->u.status.callstate.state == UNI_CALLSTATE_REST1 && 783 uni->glob_respond == UNI_CALLSTATE_REST0) || 784 (u->u.status.callstate.state == UNI_CALLSTATE_REST1 && 785 uni->glob_respond == UNI_CALLSTATE_REST2)) { 786 /* 787 * Implementation dependend procedure: 788 * Inform the API 789 */ 790 struct uniapi_reset_status_indication *resp; 791 struct uni_msg *app; 792 793 resp = ALLOC_API(struct uniapi_reset_status_indication, app); 794 if (resp == NULL) 795 return; 796 797 resp->cref = u->u.hdr.cref; 798 resp->callstate = u->u.status.callstate; 799 if (IE_ISGOOD(u->u.status.cause)) 800 resp->cause = u->u.status.cause; 801 802 uni->funcs->uni_output(uni, uni->arg, 803 UNIAPI_RESET_STATUS_indication, 0, app); 804 805 } else { 806 struct uniapi_reset_error_indication *resp; 807 struct uni_msg *app; 808 809 resp = ALLOC_API(struct uniapi_reset_error_indication, app); 810 if (resp != NULL) { 811 resp->source = 1; 812 resp->reason = UNIAPI_RESET_ERROR_PEER_INCOMP_STATE, 813 814 uni->funcs->uni_output(uni, uni->arg, 815 UNIAPI_RESET_ERROR_indication, 0, app); 816 } 817 } 818} 819 820/* 821 * T317 timeout function 822 */ 823static void 824t317_func(struct uni *uni) 825{ 826 uni_enq_resp(uni, SIGR_T317, 0, NULL, NULL); 827} 828