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