2 * Copyright (c) 1996-2003
3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
6 * Author: Hartmut Brandt <harti@freebsd.org>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
29 * $Begemot: libunimsg/netnatm/sig/sig_reset.c,v 1.11 2004/08/05 07:11:03 brandt Exp $
31 * Reset-start and reset-respond
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>
40 #include <netnatm/sig/unipriv.h>
41 #include <netnatm/sig/unimkmsg.h>
43 static void response_restart(struct uni *, struct uni_msg *, struct uni_all *);
44 static void response_status(struct uni *, struct uni_msg *, struct uni_all *);
46 static void response_t317(struct uni *);
48 static void response_error(struct uni *, struct uniapi_reset_error_response *,
50 static void response_response(struct uni *, struct uniapi_reset_response *,
53 static void start_request(struct uni *, struct uniapi_reset_request *,
56 static void start_t316(struct uni *);
58 static void start_restart_ack(struct uni *, struct uni_msg *, struct uni_all *);
59 static void start_status(struct uni *, struct uni_msg *, struct uni_all *);
61 static int restart_forward(struct uni *, const struct uni_all *);
63 #define DEF_PRIV_SIG(NAME, FROM) [SIG##NAME] = "SIG"#NAME,
64 static const char *const start_sigs[] = {
69 #define DEF_PRIV_SIG(NAME, FROM) [SIG##NAME] = "SIG"#NAME,
70 static const char *const respond_sigs[] = {
75 TIMER_FUNC_UNI(t317, t317_func)
76 TIMER_FUNC_UNI(t316, t316_func)
79 * Reset-Start process.
82 uni_sig_start(struct uni *uni, u_int sig, uint32_t cookie,
83 struct uni_msg *m, struct uni_all *u)
85 if (sig >= SIGS_END) {
86 VERBOSE(uni, UNI_FAC_ERR, 1, "Signal %d outside of range to "
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);
104 case SIGS_RESET_request:
106 uni_msg_rptr(m, struct uniapi_reset_request *), cookie);
120 case SIGS_RESTART_ACK:
121 start_restart_ack(uni, m, u);
127 start_status(uni, m, u);
138 * Reset-request from USER.
140 * Q.2931:Reset-Start 1/2
143 start_request(struct uni *uni, struct uniapi_reset_request *req, uint32_t cookie)
145 struct uni_all *resp;
148 if (uni->glob_start != UNI_CALLSTATE_REST0) {
149 uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0);
153 if ((resp = UNI_ALLOC()) == NULL) {
154 uniapi_uni_error(uni, UNIAPI_ERROR_NOMEM, cookie, 0);
158 MK_MSG_ORIG(resp, UNI_RESTART, 0, 0);
159 resp->u.restart.restart = req->restart;
160 resp->u.restart.connid = req->connid;
162 if (restart_forward(uni, resp))
165 uni->connid_start = req->connid;
166 uni->restart_start = req->restart;
168 if ((err = uni_send_output(resp, uni)) != 0)
169 uniapi_uni_error(uni, UNIAPI_ERROR_ENCODING, cookie, 0);
175 TIMER_START_UNI(uni, t316, uni->timer316);
176 uni->glob_start = UNI_CALLSTATE_REST1;
178 VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 1");
181 uniapi_uni_error(uni, UNIAPI_OK, cookie, 0);
185 * T316 timeout function
188 t316_func(struct uni *uni)
190 uni_enq_start(uni, SIGS_T316, 0, NULL, NULL);
194 * Q.2931:Reset-Start 1/2
197 start_t316(struct uni *uni)
199 if (uni->glob_start != UNI_CALLSTATE_REST1) {
200 VERBOSE0(uni, UNI_FAC_ERR, "T316 in state %d",
205 if (++uni->cnt316 == uni->init316) {
207 struct uniapi_reset_error_indication *resp;
209 VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start error");
211 resp = ALLOC_API(struct uniapi_reset_error_indication, app);
214 resp->reason = UNIAPI_RESET_ERROR_NO_RESPONSE,
216 uni->funcs->uni_output(uni, uni->arg,
217 UNIAPI_RESET_ERROR_indication, 0, app);
220 uni->glob_start = UNI_CALLSTATE_REST0;
221 VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 0");
223 struct uni_all *resp;
225 if ((resp = UNI_ALLOC()) == NULL)
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;
232 (void)uni_send_output(resp, uni);
236 TIMER_START_UNI(uni, t316, uni->timer316);
244 start_restart_ack(struct uni *uni, struct uni_msg *m, struct uni_all *u)
246 enum uni_callstate new_state;
247 struct uniapi_reset_confirm *conf;
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);
256 if (uni->glob_start != UNI_CALLSTATE_REST1) {
257 ASSERT(0, ("bad global call state in Reset-Start"));
262 * If body decoding fails, this is because IEs are wrong.
264 (void)uni_decode_body(m, u, &uni->cx);
265 MANDATE_IE(uni, u->u.restart_ack.restart, UNI_IE_RESTART);
267 if (IE_ISGOOD(u->u.restart_ack.restart)) {
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,
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);
282 * Compare the information elements now, because
283 * we may need the new callstate for the status message
286 new_state = UNI_CALLSTATE_REST1;
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;
297 switch (uni_verify(uni, u->u.hdr.act)) {
300 uni_respond_status_verify(uni, &u->u.hdr.cref,
301 UNI_CALLSTATE_REST1, NULL, 0);
306 uni->glob_start = UNI_CALLSTATE_REST0;
307 VERBOSE(uni, UNI_FAC_RESTART, 1,
308 "Reset-Start state := 0");
313 uni_respond_status_verify(uni, &u->u.hdr.cref,
319 if (new_state == UNI_CALLSTATE_REST1)
326 * Build restart.confirm signal for application
328 if (!IE_ISGOOD(u->u.restart_ack.connid))
329 u->u.restart.connid.h.present = 0;
332 if ((conf = ALLOC_API(struct uniapi_reset_confirm, app)) == NULL)
334 conf->restart = u->u.restart.restart;
335 conf->connid = u->u.restart.connid;
337 TIMER_STOP_UNI(uni, t316);
339 uni->funcs->uni_output(uni, uni->arg, UNIAPI_RESET_confirm, 0, app);
341 uni->glob_start = UNI_CALLSTATE_REST0;
342 VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 0");
346 * Reset-Start got a STATUS message.
348 * Q.2931: Reset-Start 2/2
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.
353 * The following states are considered compatible:
355 * Sender Receiver(we)
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!
363 * All others are wrong.
366 start_status(struct uni *uni, struct uni_msg *m, struct uni_all *u)
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)) {
373 uni->glob_start = UNI_CALLSTATE_REST0;
374 VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 0");
381 uni_respond_status_verify(uni, &u->u.hdr.cref, uni->glob_start,
387 if (!IE_ISGOOD(u->u.status.callstate)) {
389 * As a result of the strange handling above, we must
390 * process a STATUS with an invalid or missing callstate!
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)) {
401 * Implementation dependend procedure:
404 struct uniapi_reset_status_indication *resp;
407 resp = ALLOC_API(struct uniapi_reset_status_indication, app);
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;
415 uni->funcs->uni_output(uni, uni->arg,
416 UNIAPI_RESET_STATUS_indication, 0, app);
419 struct uniapi_reset_error_indication *resp;
422 resp = ALLOC_API(struct uniapi_reset_error_indication, app);
425 resp->reason = UNIAPI_RESET_ERROR_PEER_INCOMP_STATE,
427 uni->funcs->uni_output(uni, uni->arg,
428 UNIAPI_RESET_ERROR_indication, 0, app);
433 /************************************************************/
435 * Reset-Respond process.
438 uni_sig_respond(struct uni *uni, u_int sig, uint32_t cookie,
439 struct uni_msg *m, struct uni_all *u)
441 if (sig >= SIGR_END) {
442 VERBOSE(uni, UNI_FAC_ERR, 1, "Signal %d outside of range to "
443 "Reset-Respond", sig);
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);
461 response_restart(uni, m, u);
467 response_status(uni, m, u);
475 case SIGR_RESET_ERROR_response:
477 uni_msg_rptr(m, struct uniapi_reset_error_response *),
482 case SIGR_RESET_response:
483 response_response(uni,
484 uni_msg_rptr(m, struct uniapi_reset_response *), cookie);
501 * Send a RELEASE_COMPLETE to all affected calls as per
505 restart_forward(struct uni *uni, const struct uni_all *u)
508 struct uni_all *resp;
510 if ((resp = UNI_ALLOC()) == NULL)
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);
529 * Respond process got a restart message.
530 * Doesn't free the messages.
533 response_restart(struct uni *uni, struct uni_msg *m, struct uni_all *u)
536 struct uniapi_reset_indication *ind;
538 if (uni->glob_respond == UNI_CALLSTATE_REST0) {
540 * If body decoding fails, this is because IEs are wrong.
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)) {
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,
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);
558 switch (uni_verify(uni, u->u.hdr.act)) {
561 uni_respond_status_verify(uni, &u->u.hdr.cref,
562 UNI_CALLSTATE_REST0, NULL, 0);
569 uni_respond_status_verify(uni, &u->u.hdr.cref,
570 UNI_CALLSTATE_REST2, NULL, 0);
574 if (!IE_ISGOOD(u->u.restart.connid))
575 u->u.restart.connid.h.present = 0;
578 * Send a RELEASE_COMPLETE to all affected calls as per
581 if (restart_forward(uni, u))
585 * Build restart signal for application
587 if ((ind = ALLOC_API(struct uniapi_reset_indication, app)) == NULL)
590 ind->restart = u->u.restart.restart;
591 ind->connid = u->u.restart.connid;
593 uni_enq_coord(uni, SIGO_RESET_indication, 0, app);
595 TIMER_START_UNI(uni, t317, uni->timer317);
596 uni->glob_respond = UNI_CALLSTATE_REST2;
598 VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond state := 2");
601 } else if (uni->glob_respond == UNI_CALLSTATE_REST2) {
603 * No need to decode the message. It is unexpected in this
604 * state so return a status.
606 uni_respond_status_mtype(uni, &u->u.hdr.cref, uni->glob_respond,
607 UNI_CAUSE_MSG_INCOMP, UNI_RESTART);
611 ASSERT(0, ("bad global call state in responder"));
615 response_t317(struct uni *uni)
617 struct uniapi_reset_error_indication *resp;
620 if (uni->glob_respond != UNI_CALLSTATE_REST2) {
621 VERBOSE0(uni, UNI_FAC_ERR, "T317 in state %d",
626 VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond error");
628 if ((resp = ALLOC_API(struct uniapi_reset_error_indication, app)) != NULL) {
630 resp->reason = UNIAPI_RESET_ERROR_NO_CONFIRM;
632 uni->funcs->uni_output(uni, uni->arg,
633 UNIAPI_RESET_ERROR_indication, 0, app);
636 uni->glob_respond = UNI_CALLSTATE_REST0;
637 VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond state := 0");
641 * Error response from USER
644 response_error(struct uni *uni, struct uniapi_reset_error_response *c,
647 struct uni_all *resp;
649 if (uni->glob_respond != UNI_CALLSTATE_REST2) {
650 uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0);
654 if ((resp = UNI_ALLOC()) == NULL) {
655 uniapi_uni_error(uni, UNIAPI_ERROR_NOMEM, cookie, 0);
659 MK_MSG_ORIG(resp, UNI_STATUS, 0, 1);
660 MK_IE_CALLSTATE(resp->u.status.callstate, UNI_CALLSTATE_REST2);
662 if (IE_ISGOOD(c->cause))
663 resp->u.status.cause = c->cause;
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);
673 if (uni_send_output(resp, uni) != 0) {
674 uniapi_uni_error(uni, UNIAPI_ERROR_ENCODING, cookie, 0);
679 uniapi_uni_error(uni, UNIAPI_OK, cookie, 0);
683 * Reset-response from user.
686 response_response(struct uni *uni, struct uniapi_reset_response *arg,
689 struct uni_all *resp;
691 if (uni->glob_respond != UNI_CALLSTATE_REST2) {
692 uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0);
696 if (!IE_ISGOOD(arg->restart)) {
697 uniapi_uni_error(uni, UNIAPI_ERROR_MISSING_IE, cookie, 0);
701 if ((resp = UNI_ALLOC()) == NULL) {
702 uniapi_uni_error(uni, UNIAPI_ERROR_NOMEM, cookie, 0);
706 TIMER_STOP_UNI(uni, t317);
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;
713 if (uni_send_output(resp, uni) != 0) {
714 uniapi_uni_error(uni, UNIAPI_ERROR_ENCODING, cookie, 0);
721 uni->glob_respond = UNI_CALLSTATE_REST0;
722 VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond state := 0");
724 uniapi_uni_error(uni, UNIAPI_OK, cookie, 0);
728 * Reset-Response got a STATUS message.
730 * Q.2931: Reset-Response 2/2
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.
735 * The following states are considered compatible:
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!
745 * All others are wrong.
748 response_status(struct uni *uni, struct uni_msg *m, struct uni_all *u)
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)) {
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");
767 uni_respond_status_verify(uni, &u->u.hdr.cref,
768 uni->glob_respond, NULL, 0);
773 if (!IE_ISGOOD(u->u.status.callstate)) {
775 * As a result of the strange handling above, we must
776 * process a STATUS with an invalid or missing callstate!
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)) {
787 * Implementation dependend procedure:
790 struct uniapi_reset_status_indication *resp;
793 resp = ALLOC_API(struct uniapi_reset_status_indication, app);
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;
802 uni->funcs->uni_output(uni, uni->arg,
803 UNIAPI_RESET_STATUS_indication, 0, app);
806 struct uniapi_reset_error_indication *resp;
809 resp = ALLOC_API(struct uniapi_reset_error_indication, app);
812 resp->reason = UNIAPI_RESET_ERROR_PEER_INCOMP_STATE,
814 uni->funcs->uni_output(uni, uni->arg,
815 UNIAPI_RESET_ERROR_indication, 0, app);
821 * T317 timeout function
824 t317_func(struct uni *uni)
826 uni_enq_resp(uni, SIGR_T317, 0, NULL, NULL);