sig_reset.c revision 133493
160786Sps/* 260786Sps * Copyright (c) 1996-2003 360786Sps * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 460786Sps * All rights reserved. 560786Sps * 660786Sps * Author: Hartmut Brandt <harti@freebsd.org> 760786Sps * 860786Sps * Redistribution and use in source and binary forms, with or without 960786Sps * modification, are permitted provided that the following conditions 1060786Sps * are met: 1160786Sps * 1. Redistributions of source code must retain the above copyright 1260786Sps * notice, this list of conditions and the following disclaimer. 1360786Sps * 2. Redistributions in binary form must reproduce the above copyright 1460786Sps * notice, this list of conditions and the following disclaimer in the 1560786Sps * documentation and/or other materials provided with the distribution. 1660786Sps * 1760786Sps * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1860786Sps * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1960786Sps * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2060786Sps * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2160786Sps * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22128345Stjr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23128345Stjr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2460786Sps * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2560786Sps * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2660786Sps * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2760786Sps * SUCH DAMAGE. 2860786Sps * 2960786Sps * $Begemot: libunimsg/netnatm/sig/sig_reset.c,v 1.11 2004/08/05 07:11:03 brandt Exp $ 3060786Sps * 3160786Sps * Reset-start and reset-respond 3260786Sps */ 3360786Sps 3460786Sps#include <netnatm/unimsg.h> 3560786Sps#include <netnatm/saal/sscfudef.h> 3660786Sps#include <netnatm/msg/unistruct.h> 3760786Sps#include <netnatm/msg/unimsglib.h> 3860786Sps#include <netnatm/sig/uni.h> 3960786Sps 4060786Sps#include <netnatm/sig/unipriv.h> 4160786Sps#include <netnatm/sig/unimkmsg.h> 4260786Sps 4360786Spsstatic void response_restart(struct uni *, struct uni_msg *, struct uni_all *); 4460786Spsstatic void response_status(struct uni *, struct uni_msg *, struct uni_all *); 4560786Sps 4660786Spsstatic void response_t317(struct uni *); 4760786Sps 4860786Spsstatic void response_error(struct uni *, struct uniapi_reset_error_response *, 4960786Sps uint32_t cookie); 5060786Spsstatic void response_response(struct uni *, struct uniapi_reset_response *, 5160786Sps uint32_t); 5260786Sps 5360786Spsstatic void start_request(struct uni *, struct uniapi_reset_request *, 5460786Sps uint32_t); 5589019Sps 5689019Spsstatic void start_t316(struct uni *); 5760786Sps 5860786Spsstatic void start_restart_ack(struct uni *, struct uni_msg *, struct uni_all *); 5960786Spsstatic void start_status(struct uni *, struct uni_msg *, struct uni_all *); 6060786Sps 6160786Spsstatic int restart_forward(struct uni *, const struct uni_all *); 6260786Sps 6360786Sps#define DEF_PRIV_SIG(NAME, FROM) [SIG##NAME] = "SIG"#NAME, 6460786Spsstatic const char *const start_sigs[] = { 6560786Sps DEF_START_SIGS 6660786Sps}; 6760786Sps#undef DEF_PRIV_SIG 6860786Sps 6960786Sps#define DEF_PRIV_SIG(NAME, FROM) [SIG##NAME] = "SIG"#NAME, 7060786Spsstatic const char *const respond_sigs[] = { 7160786Sps DEF_RESPOND_SIGS 7260786Sps}; 7360786Sps#undef DEF_PRIV_SIG 7460786Sps 7560786SpsTIMER_FUNC_UNI(t317, t317_func) 7660786SpsTIMER_FUNC_UNI(t316, t316_func) 7760786Sps 7860786Sps/* 7960786Sps * Reset-Start process. 8060786Sps */ 8160786Spsvoid 8260786Spsuni_sig_start(struct uni *uni, u_int sig, uint32_t cookie, 8360786Sps struct uni_msg *m, struct uni_all *u) 8460786Sps{ 8560786Sps if (sig >= SIGS_END) { 8660786Sps VERBOSE(uni, UNI_FAC_ERR, 1, "Signal %d outside of range to " 8760786Sps "Reset-Start", sig); 8860786Sps if (m) 8960786Sps uni_msg_destroy(m); 9060786Sps if (u) 9160786Sps UNI_FREE(u); 9260786Sps return; 9360786Sps } 9460786Sps 9560786Sps VERBOSE(uni, UNI_FAC_RESTART, 1, 9660786Sps "Signal %s in state %u of Reset-Start; cookie %u", 9760786Sps start_sigs[sig], uni->glob_start, cookie); 9860786Sps 9960786Sps switch (sig) { 10060786Sps 10160786Sps /* 10260786Sps * User requests 10360786Sps */ 10460786Sps case SIGS_RESET_request: 10560786Sps start_request(uni, 10660786Sps uni_msg_rptr(m, struct uniapi_reset_request *), cookie); 10760786Sps uni_msg_destroy(m); 10860786Sps break; 10960786Sps 11060786Sps /* 11160786Sps * Timers 11260786Sps */ 11360786Sps case SIGS_T316: 11460786Sps start_t316(uni); 11560786Sps break; 11660786Sps 11760786Sps /* 11860786Sps * SAAL 11960786Sps */ 12060786Sps case SIGS_RESTART_ACK: 12160786Sps start_restart_ack(uni, m, u); 12260786Sps uni_msg_destroy(m); 12360786Sps UNI_FREE(u); 12460786Sps break; 12560786Sps 12660786Sps case SIGS_STATUS: 12760786Sps start_status(uni, m, u); 12860786Sps uni_msg_destroy(m); 12960786Sps UNI_FREE(u); 13060786Sps break; 13160786Sps 13260786Sps case SIGS_END: 13360786Sps break; 13460786Sps } 13560786Sps} 13660786Sps 13760786Sps/* 13860786Sps * Reset-request from USER. 13960786Sps * 14060786Sps * Q.2931:Reset-Start 1/2 14160786Sps */ 14263128Spsstatic void 14363128Spsstart_request(struct uni *uni, struct uniapi_reset_request *req, uint32_t cookie) 14460786Sps{ 14560786Sps struct uni_all *resp; 146128345Stjr int err; 147128345Stjr 14860786Sps if (uni->glob_start != UNI_CALLSTATE_REST0) { 14960786Sps uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0); 15060786Sps return; 15160786Sps } 15260786Sps 15360786Sps if ((resp = UNI_ALLOC()) == NULL) { 15460786Sps uniapi_uni_error(uni, UNIAPI_ERROR_NOMEM, cookie, 0); 15560786Sps return; 15660786Sps } 15760786Sps 15860786Sps MK_MSG_ORIG(resp, UNI_RESTART, 0, 0); 15960786Sps resp->u.restart.restart = req->restart; 16060786Sps resp->u.restart.connid = req->connid; 16160786Sps 16260786Sps if (restart_forward(uni, resp)) 16360786Sps return; 16460786Sps 16560786Sps uni->connid_start = req->connid; 16660786Sps uni->restart_start = req->restart; 16760786Sps 16860786Sps if ((err = uni_send_output(resp, uni)) != 0) 16960786Sps uniapi_uni_error(uni, UNIAPI_ERROR_ENCODING, cookie, 0); 17060786Sps UNI_FREE(resp); 17160786Sps if (err) 17260786Sps return; 17360786Sps 17460786Sps uni->cnt316 = 0; 17560786Sps TIMER_START_UNI(uni, t316, uni->timer316); 17660786Sps uni->glob_start = UNI_CALLSTATE_REST1; 17760786Sps 17860786Sps VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 1"); 17960786Sps 18089019Sps 18160786Sps uniapi_uni_error(uni, UNIAPI_OK, cookie, 0); 18260786Sps} 18360786Sps 18489019Sps/* 18589019Sps * T316 timeout function 18660786Sps */ 18760786Spsstatic void 18860786Spst316_func(struct uni *uni) 18960786Sps{ 19060786Sps uni_enq_start(uni, SIGS_T316, 0, NULL, NULL); 19160786Sps} 19260786Sps 19360786Sps/* 19463128Sps * Q.2931:Reset-Start 1/2 19563128Sps */ 19663128Spsstatic void 19760786Spsstart_t316(struct uni *uni) 19860786Sps{ 19960786Sps if (uni->glob_start != UNI_CALLSTATE_REST1) { 20060786Sps VERBOSE0(uni, UNI_FAC_ERR, "T316 in state %d", 20160786Sps uni->glob_start); 20260786Sps return; 20360786Sps } 20460786Sps 20560786Sps if (++uni->cnt316 == uni->init316) { 20660786Sps struct uni_msg *app; 20760786Sps struct uniapi_reset_error_indication *resp; 20860786Sps 20960786Sps VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start error"); 21060786Sps 21160786Sps resp = ALLOC_API(struct uniapi_reset_error_indication, app); 21260786Sps if (resp != NULL) { 21360786Sps resp->source = 0; 21460786Sps resp->reason = UNIAPI_RESET_ERROR_NO_RESPONSE, 21560786Sps 21660786Sps uni->funcs->uni_output(uni, uni->arg, 21760786Sps UNIAPI_RESET_ERROR_indication, 0, app); 21860786Sps } 21960786Sps 22060786Sps 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 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 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