diff options
Diffstat (limited to 'sys/contrib/ngatm/netnatm/sig/sig_reset.c')
-rw-r--r-- | sys/contrib/ngatm/netnatm/sig/sig_reset.c | 827 |
1 files changed, 827 insertions, 0 deletions
diff --git a/sys/contrib/ngatm/netnatm/sig/sig_reset.c b/sys/contrib/ngatm/netnatm/sig/sig_reset.c new file mode 100644 index 0000000..29a57bd --- /dev/null +++ b/sys/contrib/ngatm/netnatm/sig/sig_reset.c @@ -0,0 +1,827 @@ +/* + * Copyright (c) 1996-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: libunimsg/netnatm/sig/sig_reset.c,v 1.11 2004/08/05 07:11:03 brandt Exp $ + * + * Reset-start and reset-respond + */ + +#include <netnatm/unimsg.h> +#include <netnatm/saal/sscfudef.h> +#include <netnatm/msg/unistruct.h> +#include <netnatm/msg/unimsglib.h> +#include <netnatm/sig/uni.h> + +#include <netnatm/sig/unipriv.h> +#include <netnatm/sig/unimkmsg.h> + +static void response_restart(struct uni *, struct uni_msg *, struct uni_all *); +static void response_status(struct uni *, struct uni_msg *, struct uni_all *); + +static void response_t317(struct uni *); + +static void response_error(struct uni *, struct uniapi_reset_error_response *, + uint32_t cookie); +static void response_response(struct uni *, struct uniapi_reset_response *, + uint32_t); + +static void start_request(struct uni *, struct uniapi_reset_request *, + uint32_t); + +static void start_t316(struct uni *); + +static void start_restart_ack(struct uni *, struct uni_msg *, struct uni_all *); +static void start_status(struct uni *, struct uni_msg *, struct uni_all *); + +static int restart_forward(struct uni *, const struct uni_all *); + +#define DEF_PRIV_SIG(NAME, FROM) [SIG##NAME] = "SIG"#NAME, +static const char *const start_sigs[] = { + DEF_START_SIGS +}; +#undef DEF_PRIV_SIG + +#define DEF_PRIV_SIG(NAME, FROM) [SIG##NAME] = "SIG"#NAME, +static const char *const respond_sigs[] = { + DEF_RESPOND_SIGS +}; +#undef DEF_PRIV_SIG + +TIMER_FUNC_UNI(t317, t317_func) +TIMER_FUNC_UNI(t316, t316_func) + +/* + * Reset-Start process. + */ +void +uni_sig_start(struct uni *uni, u_int sig, uint32_t cookie, + struct uni_msg *m, struct uni_all *u) +{ + if (sig >= SIGS_END) { + VERBOSE(uni, UNI_FAC_ERR, 1, "Signal %d outside of range to " + "Reset-Start", sig); + if (m) + uni_msg_destroy(m); + if (u) + UNI_FREE(u); + return; + } + + VERBOSE(uni, UNI_FAC_RESTART, 1, + "Signal %s in state %u of Reset-Start; cookie %u", + start_sigs[sig], uni->glob_start, cookie); + + switch (sig) { + + /* + * User requests + */ + case SIGS_RESET_request: + start_request(uni, + uni_msg_rptr(m, struct uniapi_reset_request *), cookie); + uni_msg_destroy(m); + break; + + /* + * Timers + */ + case SIGS_T316: + start_t316(uni); + break; + + /* + * SAAL + */ + case SIGS_RESTART_ACK: + start_restart_ack(uni, m, u); + uni_msg_destroy(m); + UNI_FREE(u); + break; + + case SIGS_STATUS: + start_status(uni, m, u); + uni_msg_destroy(m); + UNI_FREE(u); + break; + + case SIGS_END: + break; + } +} + +/* + * Reset-request from USER. + * + * Q.2931:Reset-Start 1/2 + */ +static void +start_request(struct uni *uni, struct uniapi_reset_request *req, uint32_t cookie) +{ + struct uni_all *resp; + int err; + + if (uni->glob_start != UNI_CALLSTATE_REST0) { + uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0); + return; + } + + if ((resp = UNI_ALLOC()) == NULL) { + uniapi_uni_error(uni, UNIAPI_ERROR_NOMEM, cookie, 0); + return; + } + + MK_MSG_ORIG(resp, UNI_RESTART, 0, 0); + resp->u.restart.restart = req->restart; + resp->u.restart.connid = req->connid; + + if (restart_forward(uni, resp)) + return; + + uni->connid_start = req->connid; + uni->restart_start = req->restart; + + if ((err = uni_send_output(resp, uni)) != 0) + uniapi_uni_error(uni, UNIAPI_ERROR_ENCODING, cookie, 0); + UNI_FREE(resp); + if (err) + return; + + uni->cnt316 = 0; + TIMER_START_UNI(uni, t316, uni->timer316); + uni->glob_start = UNI_CALLSTATE_REST1; + + VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 1"); + + + uniapi_uni_error(uni, UNIAPI_OK, cookie, 0); +} + +/* + * T316 timeout function + */ +static void +t316_func(struct uni *uni) +{ + uni_enq_start(uni, SIGS_T316, 0, NULL, NULL); +} + +/* + * Q.2931:Reset-Start 1/2 + */ +static void +start_t316(struct uni *uni) +{ + if (uni->glob_start != UNI_CALLSTATE_REST1) { + VERBOSE0(uni, UNI_FAC_ERR, "T316 in state %d", + uni->glob_start); + return; + } + + if (++uni->cnt316 == uni->init316) { + struct uni_msg *app; + struct uniapi_reset_error_indication *resp; + + VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start error"); + + resp = ALLOC_API(struct uniapi_reset_error_indication, app); + if (resp != NULL) { + resp->source = 0; + resp->reason = UNIAPI_RESET_ERROR_NO_RESPONSE, + + uni->funcs->uni_output(uni, uni->arg, + UNIAPI_RESET_ERROR_indication, 0, app); + } + + uni->glob_start = UNI_CALLSTATE_REST0; + VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 0"); + } else { + struct uni_all *resp; + + if ((resp = UNI_ALLOC()) == NULL) + return; + + MK_MSG_ORIG(resp, UNI_RESTART, 0, 0); + resp->u.restart.restart = uni->restart_start; + resp->u.restart.connid = uni->connid_start; + + (void)uni_send_output(resp, uni); + + UNI_FREE(resp); + + TIMER_START_UNI(uni, t316, uni->timer316); + } +} + +/* + * Got RESTART_ACK. + */ +static void +start_restart_ack(struct uni *uni, struct uni_msg *m, struct uni_all *u) +{ + enum uni_callstate new_state; + struct uniapi_reset_confirm *conf; + struct uni_msg *app; + + if (uni->glob_start == UNI_CALLSTATE_REST0) { + uni_respond_status_mtype(uni, &u->u.hdr.cref, uni->glob_start, + UNI_CAUSE_MSG_INCOMP, UNI_RESTART_ACK); + return; + } + + if (uni->glob_start != UNI_CALLSTATE_REST1) { + ASSERT(0, ("bad global call state in Reset-Start")); + return; + } + + /* + * If body decoding fails, this is because IEs are wrong. + */ + (void)uni_decode_body(m, u, &uni->cx); + MANDATE_IE(uni, u->u.restart_ack.restart, UNI_IE_RESTART); + + if (IE_ISGOOD(u->u.restart_ack.restart)) { + /* + * Q.2931: 5.5.2.2 + */ + if (u->u.restart_ack.restart.rclass == UNI_RESTART_ALL && + IE_ISGOOD(u->u.restart_ack.connid)) { + UNI_SAVE_IERR(&uni->cx, UNI_IE_CONNID, + u->u.restart_ack.connid.h.act, + UNI_IERR_UNK); + } else if ((u->u.restart_ack.restart.rclass == UNI_RESTART_PATH || + u->u.restart_ack.restart.rclass == UNI_RESTART_CHANNEL)) { + MANDATE_IE(uni, u->u.restart_ack.connid, UNI_IE_CONNID); + } + } + /* + * Compare the information elements now, because + * we may need the new callstate for the status message + * below. + */ + new_state = UNI_CALLSTATE_REST1; + + if (IE_ISGOOD(u->u.restart_ack.restart) && + IE_ISGOOD(uni->restart_start) && + u->u.restart_ack.restart.rclass == uni->restart_start.rclass && + !IE_ISGOOD(u->u.restart_ack.connid) == !IE_ISGOOD(uni->connid_start) && + (!IE_ISGOOD(uni->connid_start) || + (u->u.restart_ack.connid.vpci == uni->connid_start.vpci && + u->u.restart_ack.connid.vci == uni->connid_start.vci))) + new_state = UNI_CALLSTATE_REST0; + + switch (uni_verify(uni, u->u.hdr.act)) { + case VFY_RAIM: + case VFY_RAI: + uni_respond_status_verify(uni, &u->u.hdr.cref, + UNI_CALLSTATE_REST1, NULL, 0); + case VFY_I: + return; + + case VFY_CLR: + uni->glob_start = UNI_CALLSTATE_REST0; + VERBOSE(uni, UNI_FAC_RESTART, 1, + "Reset-Start state := 0"); + return; + + case VFY_RAP: + case VFY_RAPU: + uni_respond_status_verify(uni, &u->u.hdr.cref, + new_state, NULL, 0); + case VFY_OK: + break; + } + + if (new_state == UNI_CALLSTATE_REST1) + /* + * Q.2931: 5.5.1.2/2 + */ + return; + + /* + * Build restart.confirm signal for application + */ + if (!IE_ISGOOD(u->u.restart_ack.connid)) + u->u.restart.connid.h.present = 0; + + + if ((conf = ALLOC_API(struct uniapi_reset_confirm, app)) == NULL) + return; + conf->restart = u->u.restart.restart; + conf->connid = u->u.restart.connid; + + TIMER_STOP_UNI(uni, t316); + + uni->funcs->uni_output(uni, uni->arg, UNIAPI_RESET_confirm, 0, app); + + uni->glob_start = UNI_CALLSTATE_REST0; + VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 0"); +} + +/* + * Reset-Start got a STATUS message. + * + * Q.2931: Reset-Start 2/2 + * + * In Q.2931 only CALLSTATE_REST1 is allowed, this seems silly and to contradict + * 5.6.12. So allow it in any state. + * + * The following states are considered compatible: + * + * Sender Receiver(we) + * ------ -------- + * Rest0 Rest0 this is the normal state OK! + * Rest2 Rest0 this may be the result of no answer from the API + * on the remote end and the us finally timing out. ERROR! + * Rest2 Rest1 this is normal. OK! + * Rest0 Rest1 RESTART_ACK was probably lost. OK! + * + * All others are wrong. + */ +static void +start_status(struct uni *uni, struct uni_msg *m, struct uni_all *u) +{ + (void)uni_decode_body(m, u, &uni->cx); + MANDATE_IE(uni, u->u.status.callstate, UNI_IE_CALLSTATE); + MANDATE_IE(uni, u->u.status.cause, UNI_IE_CAUSE); + switch (uni_verify(uni, u->u.hdr.act)) { + case VFY_CLR: + uni->glob_start = UNI_CALLSTATE_REST0; + VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 0"); + return; + + case VFY_RAIM: + case VFY_RAI: + case VFY_RAP: + case VFY_RAPU: + uni_respond_status_verify(uni, &u->u.hdr.cref, uni->glob_start, + NULL, 0); + case VFY_I: + case VFY_OK: + break; + } + if (!IE_ISGOOD(u->u.status.callstate)) { + /* + * As a result of the strange handling above, we must + * process a STATUS with an invalid or missing callstate! + */ + return; + } + if ((u->u.status.callstate.state == UNI_CALLSTATE_REST0 && + uni->glob_start == UNI_CALLSTATE_REST0) || + (u->u.status.callstate.state == UNI_CALLSTATE_REST0 && + uni->glob_start == UNI_CALLSTATE_REST1) || + (u->u.status.callstate.state == UNI_CALLSTATE_REST2 && + uni->glob_start == UNI_CALLSTATE_REST1)) { + /* + * Implementation dependend procedure: + * Inform the API + */ + struct uniapi_reset_status_indication *resp; + struct uni_msg *app; + + resp = ALLOC_API(struct uniapi_reset_status_indication, app); + if (resp == NULL) + return; + resp->cref = u->u.hdr.cref; + resp->callstate = u->u.status.callstate; + if (IE_ISGOOD(u->u.status.cause)) + resp->cause = u->u.status.cause; + + uni->funcs->uni_output(uni, uni->arg, + UNIAPI_RESET_STATUS_indication, 0, app); + + } else { + struct uniapi_reset_error_indication *resp; + struct uni_msg *app; + + resp = ALLOC_API(struct uniapi_reset_error_indication, app); + if (resp != NULL) { + resp->source = 0; + resp->reason = UNIAPI_RESET_ERROR_PEER_INCOMP_STATE, + + uni->funcs->uni_output(uni, uni->arg, + UNIAPI_RESET_ERROR_indication, 0, app); + } + } +} + +/************************************************************/ +/* + * Reset-Respond process. + */ +void +uni_sig_respond(struct uni *uni, u_int sig, uint32_t cookie, + struct uni_msg *m, struct uni_all *u) +{ + if (sig >= SIGR_END) { + VERBOSE(uni, UNI_FAC_ERR, 1, "Signal %d outside of range to " + "Reset-Respond", sig); + if (m) + uni_msg_destroy(m); + if (u) + UNI_FREE(u); + return; + } + + VERBOSE(uni, UNI_FAC_RESTART, 1, + "Signal %s in state %u of Reset-Respond; cookie %u", + respond_sigs[sig], uni->glob_respond, cookie); + + switch (sig) { + + /* + * SAAL + */ + case SIGR_RESTART: + response_restart(uni, m, u); + uni_msg_destroy(m); + UNI_FREE(u); + break; + + case SIGR_STATUS: + response_status(uni, m, u); + uni_msg_destroy(m); + UNI_FREE(u); + break; + + /* + * User + */ + case SIGR_RESET_ERROR_response: + response_error(uni, + uni_msg_rptr(m, struct uniapi_reset_error_response *), + cookie); + uni_msg_destroy(m); + break; + + case SIGR_RESET_response: + response_response(uni, + uni_msg_rptr(m, struct uniapi_reset_response *), cookie); + uni_msg_destroy(m); + break; + + /* + * Timers + */ + case SIGR_T317: + response_t317(uni); + return; + + case SIGR_END: + break; + } +} + +/* + * Send a RELEASE_COMPLETE to all affected calls as per + * F.2.3(3) + */ +static int +restart_forward(struct uni *uni, const struct uni_all *u) +{ + struct call *c; + struct uni_all *resp; + + if ((resp = UNI_ALLOC()) == NULL) + return (-1); + + TAILQ_FOREACH(c, &uni->calls, link) { + if (u->u.restart.restart.rclass == UNI_RESTART_ALL || + (IE_ISPRESENT(c->connid) && + u->u.restart.connid.vpci == c->connid.vpci && + (u->u.restart.restart.rclass == UNI_RESTART_PATH || + u->u.restart.connid.vci == c->connid.vci))) { + MK_MSG_ORIG(resp, UNI_RELEASE_COMPL, c->cref, c->mine); + uni_release_compl(c, resp); + } + } + + UNI_FREE(resp); + return (0); +} + +/* + * Respond process got a restart message. + * Doesn't free the messages. + */ +static void +response_restart(struct uni *uni, struct uni_msg *m, struct uni_all *u) +{ + struct uni_msg *app; + struct uniapi_reset_indication *ind; + + if (uni->glob_respond == UNI_CALLSTATE_REST0) { + /* + * If body decoding fails, this is because IEs are wrong. + */ + (void)uni_decode_body(m, u, &uni->cx); + MANDATE_IE(uni, u->u.restart.restart, UNI_IE_RESTART); + if (IE_ISGOOD(u->u.restart.restart)) { + /* + * Q.2931: 5.5.2.2 + */ + if (u->u.restart.restart.rclass == UNI_RESTART_ALL && + IE_ISGOOD(u->u.restart.connid)) { + UNI_SAVE_IERR(&uni->cx, UNI_IE_CONNID, + u->u.restart.connid.h.act, + UNI_IERR_UNK); + } else if ((u->u.restart.restart.rclass == UNI_RESTART_PATH || + u->u.restart.restart.rclass == UNI_RESTART_CHANNEL)) { + MANDATE_IE(uni, u->u.restart.connid, UNI_IE_CONNID); + } + } + switch (uni_verify(uni, u->u.hdr.act)) { + case VFY_RAIM: + case VFY_RAI: + uni_respond_status_verify(uni, &u->u.hdr.cref, + UNI_CALLSTATE_REST0, NULL, 0); + case VFY_CLR: + case VFY_I: + return; + + case VFY_RAP: + case VFY_RAPU: + uni_respond_status_verify(uni, &u->u.hdr.cref, + UNI_CALLSTATE_REST2, NULL, 0); + case VFY_OK: + break; + } + if (!IE_ISGOOD(u->u.restart.connid)) + u->u.restart.connid.h.present = 0; + + /* + * Send a RELEASE_COMPLETE to all affected calls as per + * F.2.3(3) + */ + if (restart_forward(uni, u)) + return; + + /* + * Build restart signal for application + */ + if ((ind = ALLOC_API(struct uniapi_reset_indication, app)) == NULL) + return; + + ind->restart = u->u.restart.restart; + ind->connid = u->u.restart.connid; + + uni_enq_coord(uni, SIGO_RESET_indication, 0, app); + + TIMER_START_UNI(uni, t317, uni->timer317); + uni->glob_respond = UNI_CALLSTATE_REST2; + + VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond state := 2"); + + + } else if (uni->glob_respond == UNI_CALLSTATE_REST2) { + /* + * No need to decode the message. It is unexpected in this + * state so return a status. + */ + uni_respond_status_mtype(uni, &u->u.hdr.cref, uni->glob_respond, + UNI_CAUSE_MSG_INCOMP, UNI_RESTART); + + + } else + ASSERT(0, ("bad global call state in responder")); +} + +static void +response_t317(struct uni *uni) +{ + struct uniapi_reset_error_indication *resp; + struct uni_msg *app; + + if (uni->glob_respond != UNI_CALLSTATE_REST2) { + VERBOSE0(uni, UNI_FAC_ERR, "T317 in state %d", + uni->glob_respond); + return; + } + + VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond error"); + + if ((resp = ALLOC_API(struct uniapi_reset_error_indication, app)) != NULL) { + resp->source = 1; + resp->reason = UNIAPI_RESET_ERROR_NO_CONFIRM; + + uni->funcs->uni_output(uni, uni->arg, + UNIAPI_RESET_ERROR_indication, 0, app); + } + + uni->glob_respond = UNI_CALLSTATE_REST0; + VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond state := 0"); +} + +/* + * Error response from USER + */ +static void +response_error(struct uni *uni, struct uniapi_reset_error_response *c, + uint32_t cookie) +{ + struct uni_all *resp; + + if (uni->glob_respond != UNI_CALLSTATE_REST2) { + uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0); + return; + } + + if ((resp = UNI_ALLOC()) == NULL) { + uniapi_uni_error(uni, UNIAPI_ERROR_NOMEM, cookie, 0); + return; + } + + MK_MSG_ORIG(resp, UNI_STATUS, 0, 1); + MK_IE_CALLSTATE(resp->u.status.callstate, UNI_CALLSTATE_REST2); + + if (IE_ISGOOD(c->cause)) + resp->u.status.cause = c->cause; + else { + MK_IE_CAUSE(resp->u.status.cause, UNI_CAUSE_LOC_USER, + UNI_CAUSE_CHANNEL_NEX); + if (IE_ISGOOD(uni->connid_respond)) + ADD_CAUSE_CHANNID(resp->u.status.cause, + uni->connid_respond.vpci, + uni->connid_respond.vci); + } + + if (uni_send_output(resp, uni) != 0) { + uniapi_uni_error(uni, UNIAPI_ERROR_ENCODING, cookie, 0); + UNI_FREE(resp); + return; + } + + uniapi_uni_error(uni, UNIAPI_OK, cookie, 0); +} + +/* + * Reset-response from user. + */ +static void +response_response(struct uni *uni, struct uniapi_reset_response *arg, + uint32_t cookie) +{ + struct uni_all *resp; + + if (uni->glob_respond != UNI_CALLSTATE_REST2) { + uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0); + return; + } + + if (!IE_ISGOOD(arg->restart)) { + uniapi_uni_error(uni, UNIAPI_ERROR_MISSING_IE, cookie, 0); + return; + } + + if ((resp = UNI_ALLOC()) == NULL) { + uniapi_uni_error(uni, UNIAPI_ERROR_NOMEM, cookie, 0); + return; + } + + TIMER_STOP_UNI(uni, t317); + + MK_MSG_ORIG(resp, UNI_RESTART_ACK, 0, 1); + resp->u.restart.restart = arg->restart; + if (IE_ISGOOD(arg->connid)) + resp->u.restart.connid = arg->connid; + + if (uni_send_output(resp, uni) != 0) { + uniapi_uni_error(uni, UNIAPI_ERROR_ENCODING, cookie, 0); + UNI_FREE(resp); + return; + } + + UNI_FREE(resp); + + uni->glob_respond = UNI_CALLSTATE_REST0; + VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond state := 0"); + + uniapi_uni_error(uni, UNIAPI_OK, cookie, 0); +} + +/* + * Reset-Response got a STATUS message. + * + * Q.2931: Reset-Response 2/2 + * + * In Q.2931 only CALLSTATE_REST2 is allowed, this seems silly and to contradict + * 5.6.12. So allow it in any state. + * + * The following states are considered compatible: + * + * Sender Receiver + * ------ -------- + * Rest0 Rest0 this is the normal state OK! + * Rest0 Rest2 this may be the result of no answer from the API + * and the Sender finally timing out. ERROR! + * Rest1 Rest2 this is normal. OK! + * Rest1 Rest0 RESTART_ACK was probably lost. OK! + * + * All others are wrong. + */ +static void +response_status(struct uni *uni, struct uni_msg *m, struct uni_all *u) +{ + (void)uni_decode_body(m, u, &uni->cx); + MANDATE_IE(uni, u->u.status.callstate, UNI_IE_CALLSTATE); + MANDATE_IE(uni, u->u.status.cause, UNI_IE_CAUSE); + switch (uni_verify(uni, u->u.hdr.act)) { + case VFY_CLR: + if (uni->proto == UNIPROTO_UNI40U) { + uni->glob_respond = UNI_CALLSTATE_REST0; + VERBOSE(uni, UNI_FAC_RESTART, 1, + "Reset-Respond state := 0"); + return; + } + break; + + case VFY_RAIM: + case VFY_RAI: + case VFY_RAP: + case VFY_RAPU: + uni_respond_status_verify(uni, &u->u.hdr.cref, + uni->glob_respond, NULL, 0); + case VFY_I: + case VFY_OK: + break; + } + if (!IE_ISGOOD(u->u.status.callstate)) { + /* + * As a result of the strange handling above, we must + * process a STATUS with an invalid or missing callstate! + */ + return; + } + if ((u->u.status.callstate.state == UNI_CALLSTATE_REST0 && + uni->glob_respond == UNI_CALLSTATE_REST0) || + (u->u.status.callstate.state == UNI_CALLSTATE_REST1 && + uni->glob_respond == UNI_CALLSTATE_REST0) || + (u->u.status.callstate.state == UNI_CALLSTATE_REST1 && + uni->glob_respond == UNI_CALLSTATE_REST2)) { + /* + * Implementation dependend procedure: + * Inform the API + */ + struct uniapi_reset_status_indication *resp; + struct uni_msg *app; + + resp = ALLOC_API(struct uniapi_reset_status_indication, app); + if (resp == NULL) + return; + + resp->cref = u->u.hdr.cref; + resp->callstate = u->u.status.callstate; + if (IE_ISGOOD(u->u.status.cause)) + resp->cause = u->u.status.cause; + + uni->funcs->uni_output(uni, uni->arg, + UNIAPI_RESET_STATUS_indication, 0, app); + + } else { + struct uniapi_reset_error_indication *resp; + struct uni_msg *app; + + resp = ALLOC_API(struct uniapi_reset_error_indication, app); + if (resp != NULL) { + resp->source = 1; + resp->reason = UNIAPI_RESET_ERROR_PEER_INCOMP_STATE, + + uni->funcs->uni_output(uni, uni->arg, + UNIAPI_RESET_ERROR_indication, 0, app); + } + } +} + +/* + * T317 timeout function + */ +static void +t317_func(struct uni *uni) +{ + uni_enq_resp(uni, SIGR_T317, 0, NULL, NULL); +} |