1122205Sharti/*
2122205Sharti * Copyright (c) 1996-2003
3122205Sharti *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4122205Sharti * 	All rights reserved.
5122205Sharti *
6131826Sharti * Author: Hartmut Brandt <harti@freebsd.org>
7131826Sharti *
8122205Sharti * Redistribution and use in source and binary forms, with or without
9122205Sharti * modification, are permitted provided that the following conditions
10122205Sharti * are met:
11122205Sharti * 1. Redistributions of source code must retain the above copyright
12122205Sharti *    notice, this list of conditions and the following disclaimer.
13122205Sharti * 2. Redistributions in binary form must reproduce the above copyright
14122205Sharti *    notice, this list of conditions and the following disclaimer in the
15122205Sharti *    documentation and/or other materials provided with the distribution.
16122205Sharti *
17122205Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18122205Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19122205Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20122205Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21122205Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22122205Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23122205Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24122205Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25122205Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26122205Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27122205Sharti * SUCH DAMAGE.
28122205Sharti *
29133492Sharti * $Begemot: libunimsg/netnatm/sig/sig_reset.c,v 1.11 2004/08/05 07:11:03 brandt Exp $
30122205Sharti *
31122205Sharti * Reset-start and reset-respond
32122205Sharti */
33122205Sharti
34122205Sharti#include <netnatm/unimsg.h>
35122205Sharti#include <netnatm/saal/sscfudef.h>
36122205Sharti#include <netnatm/msg/unistruct.h>
37122205Sharti#include <netnatm/msg/unimsglib.h>
38122205Sharti#include <netnatm/sig/uni.h>
39122205Sharti
40122205Sharti#include <netnatm/sig/unipriv.h>
41122205Sharti#include <netnatm/sig/unimkmsg.h>
42122205Sharti
43122205Shartistatic void response_restart(struct uni *, struct uni_msg *, struct uni_all *);
44122205Shartistatic void response_status(struct uni *, struct uni_msg *, struct uni_all *);
45122205Sharti
46122205Shartistatic void response_t317(struct uni *);
47122205Sharti
48131826Shartistatic void response_error(struct uni *, struct uniapi_reset_error_response *,
49131826Sharti    uint32_t cookie);
50131826Shartistatic void response_response(struct uni *, struct uniapi_reset_response *,
51131826Sharti    uint32_t);
52122205Sharti
53131826Shartistatic void start_request(struct uni *, struct uniapi_reset_request *,
54131826Sharti    uint32_t);
55122205Sharti
56122205Shartistatic void start_t316(struct uni *);
57122205Sharti
58122205Shartistatic void start_restart_ack(struct uni *, struct uni_msg *, struct uni_all *);
59122205Shartistatic void start_status(struct uni *, struct uni_msg *, struct uni_all *);
60122205Sharti
61122205Shartistatic int restart_forward(struct uni *, const struct uni_all *);
62122205Sharti
63133492Sharti#define DEF_PRIV_SIG(NAME, FROM)	[SIG##NAME] =	"SIG"#NAME,
64122205Shartistatic const char *const start_sigs[] = {
65122205Sharti	DEF_START_SIGS
66122205Sharti};
67122205Sharti#undef DEF_PRIV_SIG
68122205Sharti
69133492Sharti#define DEF_PRIV_SIG(NAME, FROM)	[SIG##NAME] =	"SIG"#NAME,
70122205Shartistatic const char *const respond_sigs[] = {
71122205Sharti	DEF_RESPOND_SIGS
72122205Sharti};
73122205Sharti#undef DEF_PRIV_SIG
74122205Sharti
75122205ShartiTIMER_FUNC_UNI(t317, t317_func)
76122205ShartiTIMER_FUNC_UNI(t316, t316_func)
77122205Sharti
78122205Sharti/*
79122205Sharti * Reset-Start process.
80122205Sharti */
81122205Shartivoid
82131826Shartiuni_sig_start(struct uni *uni, u_int sig, uint32_t cookie,
83122205Sharti    struct uni_msg *m, struct uni_all *u)
84122205Sharti{
85122205Sharti	if (sig >= SIGS_END) {
86122205Sharti		VERBOSE(uni, UNI_FAC_ERR, 1, "Signal %d outside of range to "
87122205Sharti		    "Reset-Start", sig);
88122205Sharti		if (m)
89122205Sharti			uni_msg_destroy(m);
90122205Sharti		if (u)
91122205Sharti			UNI_FREE(u);
92122205Sharti		return;
93122205Sharti	}
94122205Sharti
95122205Sharti	VERBOSE(uni, UNI_FAC_RESTART, 1,
96122205Sharti	    "Signal %s in state %u of Reset-Start; cookie %u",
97122205Sharti	    start_sigs[sig], uni->glob_start, cookie);
98122205Sharti
99122205Sharti	switch (sig) {
100122205Sharti
101122205Sharti	/*
102122205Sharti	 * User requests
103122205Sharti	 */
104122205Sharti	  case SIGS_RESET_request:
105122205Sharti		start_request(uni,
106122205Sharti		    uni_msg_rptr(m, struct uniapi_reset_request *), cookie);
107122205Sharti		uni_msg_destroy(m);
108122205Sharti		break;
109122205Sharti
110122205Sharti	/*
111122205Sharti	 * Timers
112122205Sharti	 */
113122205Sharti	  case SIGS_T316:
114122205Sharti		start_t316(uni);
115122205Sharti		break;
116122205Sharti
117122205Sharti	/*
118122205Sharti	 * SAAL
119122205Sharti	 */
120122205Sharti	  case SIGS_RESTART_ACK:
121122205Sharti		start_restart_ack(uni, m, u);
122122205Sharti		uni_msg_destroy(m);
123122205Sharti		UNI_FREE(u);
124122205Sharti		break;
125122205Sharti
126122205Sharti	  case SIGS_STATUS:
127122205Sharti		start_status(uni, m, u);
128122205Sharti		uni_msg_destroy(m);
129122205Sharti		UNI_FREE(u);
130122205Sharti		break;
131122205Sharti
132122205Sharti	  case SIGS_END:
133122205Sharti		break;
134122205Sharti	}
135122205Sharti}
136122205Sharti
137122205Sharti/*
138122205Sharti * Reset-request from USER.
139122205Sharti *
140122205Sharti * Q.2931:Reset-Start 1/2
141122205Sharti */
142122205Shartistatic void
143131826Shartistart_request(struct uni *uni, struct uniapi_reset_request *req, uint32_t cookie)
144122205Sharti{
145122205Sharti	struct uni_all *resp;
146122205Sharti	int err;
147122205Sharti
148122205Sharti	if (uni->glob_start != UNI_CALLSTATE_REST0) {
149122205Sharti		uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0);
150122205Sharti		return;
151122205Sharti	}
152122205Sharti
153122205Sharti	if ((resp = UNI_ALLOC()) == NULL) {
154122205Sharti		uniapi_uni_error(uni, UNIAPI_ERROR_NOMEM, cookie, 0);
155122205Sharti		return;
156122205Sharti	}
157122205Sharti
158122205Sharti	MK_MSG_ORIG(resp, UNI_RESTART, 0, 0);
159122205Sharti	resp->u.restart.restart = req->restart;
160122205Sharti	resp->u.restart.connid = req->connid;
161122205Sharti
162122205Sharti	if (restart_forward(uni, resp))
163122205Sharti		return;
164122205Sharti
165122205Sharti	uni->connid_start = req->connid;
166122205Sharti	uni->restart_start = req->restart;
167122205Sharti
168122205Sharti	if ((err = uni_send_output(resp, uni)) != 0)
169122205Sharti		uniapi_uni_error(uni, UNIAPI_ERROR_ENCODING, cookie, 0);
170122205Sharti	UNI_FREE(resp);
171122205Sharti	if (err)
172122205Sharti		return;
173122205Sharti
174122205Sharti	uni->cnt316 = 0;
175122205Sharti	TIMER_START_UNI(uni, t316, uni->timer316);
176122205Sharti	uni->glob_start = UNI_CALLSTATE_REST1;
177122205Sharti
178122205Sharti	VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 1");
179122205Sharti
180122205Sharti
181122205Sharti	uniapi_uni_error(uni, UNIAPI_OK, cookie, 0);
182122205Sharti}
183122205Sharti
184122205Sharti/*
185122205Sharti * T316 timeout function
186122205Sharti */
187122205Shartistatic void
188122205Shartit316_func(struct uni *uni)
189122205Sharti{
190122205Sharti	uni_enq_start(uni, SIGS_T316, 0, NULL, NULL);
191122205Sharti}
192122205Sharti
193122205Sharti/*
194122205Sharti * Q.2931:Reset-Start 1/2
195122205Sharti */
196122205Shartistatic void
197122205Shartistart_t316(struct uni *uni)
198122205Sharti{
199122205Sharti	if (uni->glob_start != UNI_CALLSTATE_REST1) {
200122205Sharti		VERBOSE0(uni, UNI_FAC_ERR, "T316 in state %d",
201122205Sharti		    uni->glob_start);
202122205Sharti		return;
203122205Sharti	}
204122205Sharti
205122205Sharti	if (++uni->cnt316 == uni->init316) {
206122205Sharti		struct uni_msg *app;
207122205Sharti		struct uniapi_reset_error_indication *resp;
208122205Sharti
209122205Sharti		VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start error");
210122205Sharti
211122205Sharti		resp = ALLOC_API(struct uniapi_reset_error_indication, app);
212122205Sharti		if (resp != NULL) {
213122205Sharti			resp->source = 0;
214122205Sharti			resp->reason = UNIAPI_RESET_ERROR_NO_RESPONSE,
215122205Sharti
216122205Sharti			uni->funcs->uni_output(uni, uni->arg,
217122205Sharti			    UNIAPI_RESET_ERROR_indication, 0, app);
218122205Sharti		}
219122205Sharti
220122205Sharti		uni->glob_start = UNI_CALLSTATE_REST0;
221122205Sharti		VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 0");
222122205Sharti	} else {
223122205Sharti		struct uni_all *resp;
224122205Sharti
225122205Sharti		if ((resp = UNI_ALLOC()) == NULL)
226122205Sharti			return;
227122205Sharti
228122205Sharti		MK_MSG_ORIG(resp, UNI_RESTART, 0, 0);
229122205Sharti		resp->u.restart.restart = uni->restart_start;
230122205Sharti		resp->u.restart.connid = uni->connid_start;
231122205Sharti
232122205Sharti		(void)uni_send_output(resp, uni);
233122205Sharti
234122205Sharti		UNI_FREE(resp);
235122205Sharti
236122205Sharti		TIMER_START_UNI(uni, t316, uni->timer316);
237122205Sharti	}
238122205Sharti}
239122205Sharti
240122205Sharti/*
241122205Sharti * Got RESTART_ACK.
242122205Sharti */
243122205Shartistatic void
244122205Shartistart_restart_ack(struct uni *uni, struct uni_msg *m, struct uni_all *u)
245122205Sharti{
246122205Sharti	enum uni_callstate new_state;
247122205Sharti	struct uniapi_reset_confirm *conf;
248122205Sharti	struct uni_msg *app;
249122205Sharti
250122205Sharti	if (uni->glob_start == UNI_CALLSTATE_REST0) {
251122205Sharti		uni_respond_status_mtype(uni, &u->u.hdr.cref, uni->glob_start,
252122205Sharti		    UNI_CAUSE_MSG_INCOMP, UNI_RESTART_ACK);
253122205Sharti		return;
254122205Sharti	}
255122205Sharti
256122205Sharti	if (uni->glob_start != UNI_CALLSTATE_REST1) {
257122205Sharti		ASSERT(0, ("bad global call state in Reset-Start"));
258122205Sharti		return;
259122205Sharti	}
260122205Sharti
261122205Sharti	/*
262122205Sharti	 * If body decoding fails, this is because IEs are wrong.
263122205Sharti	 */
264122205Sharti	(void)uni_decode_body(m, u, &uni->cx);
265122205Sharti	MANDATE_IE(uni, u->u.restart_ack.restart, UNI_IE_RESTART);
266122205Sharti
267122205Sharti	if (IE_ISGOOD(u->u.restart_ack.restart)) {
268122205Sharti		/*
269122205Sharti		 * Q.2931: 5.5.2.2
270122205Sharti		 */
271122205Sharti		if (u->u.restart_ack.restart.rclass == UNI_RESTART_ALL &&
272122205Sharti		    IE_ISGOOD(u->u.restart_ack.connid)) {
273213789Srpaulo			(void)UNI_SAVE_IERR(&uni->cx, UNI_IE_CONNID,
274122205Sharti			    u->u.restart_ack.connid.h.act,
275122205Sharti			    UNI_IERR_UNK);
276122205Sharti		} else if ((u->u.restart_ack.restart.rclass == UNI_RESTART_PATH ||
277122205Sharti			    u->u.restart_ack.restart.rclass == UNI_RESTART_CHANNEL)) {
278122205Sharti			MANDATE_IE(uni, u->u.restart_ack.connid, UNI_IE_CONNID);
279122205Sharti		}
280122205Sharti	}
281122205Sharti	/*
282122205Sharti	 * Compare the information elements now, because
283122205Sharti	 * we may need the new callstate for the status message
284122205Sharti	 * below.
285122205Sharti	 */
286122205Sharti	new_state = UNI_CALLSTATE_REST1;
287122205Sharti
288122205Sharti	if (IE_ISGOOD(u->u.restart_ack.restart) &&
289122205Sharti	    IE_ISGOOD(uni->restart_start) &&
290122205Sharti	    u->u.restart_ack.restart.rclass == uni->restart_start.rclass &&
291122205Sharti	    !IE_ISGOOD(u->u.restart_ack.connid) == !IE_ISGOOD(uni->connid_start) &&
292122205Sharti	    (!IE_ISGOOD(uni->connid_start) ||
293122205Sharti	       (u->u.restart_ack.connid.vpci == uni->connid_start.vpci &&
294122205Sharti	        u->u.restart_ack.connid.vci == uni->connid_start.vci)))
295122205Sharti		new_state = UNI_CALLSTATE_REST0;
296122205Sharti
297122205Sharti	switch (uni_verify(uni, u->u.hdr.act)) {
298122205Sharti	  case VFY_RAIM:
299122205Sharti	  case VFY_RAI:
300122205Sharti		uni_respond_status_verify(uni, &u->u.hdr.cref,
301122205Sharti		    UNI_CALLSTATE_REST1, NULL, 0);
302122205Sharti	  case VFY_I:
303122205Sharti		return;
304122205Sharti
305122205Sharti	  case VFY_CLR:
306122205Sharti		uni->glob_start = UNI_CALLSTATE_REST0;
307122205Sharti		VERBOSE(uni, UNI_FAC_RESTART, 1,
308122205Sharti		    "Reset-Start state := 0");
309122205Sharti		return;
310122205Sharti
311122205Sharti	  case VFY_RAP:
312122205Sharti	  case VFY_RAPU:
313122205Sharti		uni_respond_status_verify(uni, &u->u.hdr.cref,
314122205Sharti		    new_state, NULL, 0);
315122205Sharti	  case VFY_OK:
316122205Sharti		break;
317122205Sharti	}
318122205Sharti
319122205Sharti	if (new_state == UNI_CALLSTATE_REST1)
320122205Sharti		/*
321122205Sharti		 * Q.2931: 5.5.1.2/2
322122205Sharti		 */
323122205Sharti		return;
324122205Sharti
325122205Sharti	/*
326122205Sharti	 * Build restart.confirm signal for application
327122205Sharti	 */
328122205Sharti	if (!IE_ISGOOD(u->u.restart_ack.connid))
329122205Sharti		u->u.restart.connid.h.present = 0;
330122205Sharti
331122205Sharti
332122205Sharti	if ((conf = ALLOC_API(struct uniapi_reset_confirm, app)) == NULL)
333122205Sharti		return;
334122205Sharti	conf->restart = u->u.restart.restart;
335122205Sharti	conf->connid = u->u.restart.connid;
336122205Sharti
337122205Sharti	TIMER_STOP_UNI(uni, t316);
338122205Sharti
339122205Sharti	uni->funcs->uni_output(uni, uni->arg, UNIAPI_RESET_confirm, 0, app);
340122205Sharti
341122205Sharti	uni->glob_start = UNI_CALLSTATE_REST0;
342122205Sharti	VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 0");
343122205Sharti}
344122205Sharti
345122205Sharti/*
346122205Sharti * Reset-Start got a STATUS message.
347122205Sharti *
348122205Sharti * Q.2931: Reset-Start 2/2
349122205Sharti *
350122205Sharti * In Q.2931 only CALLSTATE_REST1 is allowed, this seems silly and to contradict
351122205Sharti * 5.6.12. So allow it in any state.
352122205Sharti *
353122205Sharti * The following states are considered compatible:
354122205Sharti *
355122205Sharti *  Sender   Receiver(we)
356122205Sharti *  ------   --------
357122205Sharti *  Rest0     Rest0	this is the normal state OK!
358122205Sharti *  Rest2     Rest0	this may be the result of no answer from the API
359122205Sharti *			on the remote end and the us finally timing out. ERROR!
360122205Sharti *  Rest2     Rest1	this is normal. OK!
361122205Sharti *  Rest0     Rest1	RESTART_ACK was probably lost. OK!
362122205Sharti *
363122205Sharti * All others are wrong.
364122205Sharti */
365122205Shartistatic void
366122205Shartistart_status(struct uni *uni, struct uni_msg *m, struct uni_all *u)
367122205Sharti{
368122205Sharti	(void)uni_decode_body(m, u, &uni->cx);
369122205Sharti	MANDATE_IE(uni, u->u.status.callstate, UNI_IE_CALLSTATE);
370122205Sharti	MANDATE_IE(uni, u->u.status.cause, UNI_IE_CAUSE);
371122205Sharti	switch (uni_verify(uni, u->u.hdr.act)) {
372122205Sharti	  case VFY_CLR:
373122205Sharti		uni->glob_start = UNI_CALLSTATE_REST0;
374122205Sharti		VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 0");
375122205Sharti		return;
376122205Sharti
377122205Sharti	  case VFY_RAIM:
378122205Sharti	  case VFY_RAI:
379122205Sharti	  case VFY_RAP:
380122205Sharti	  case VFY_RAPU:
381122205Sharti		uni_respond_status_verify(uni, &u->u.hdr.cref, uni->glob_start,
382122205Sharti		    NULL, 0);
383122205Sharti	  case VFY_I:
384122205Sharti	  case VFY_OK:
385122205Sharti		break;
386122205Sharti	}
387122205Sharti	if (!IE_ISGOOD(u->u.status.callstate)) {
388122205Sharti		/*
389122205Sharti		 * As a result of the strange handling above, we must
390122205Sharti		 * process a STATUS with an invalid or missing callstate!
391122205Sharti		 */
392122205Sharti		return;
393122205Sharti	}
394122205Sharti	if ((u->u.status.callstate.state == UNI_CALLSTATE_REST0 &&
395122205Sharti	     uni->glob_start == UNI_CALLSTATE_REST0) ||
396122205Sharti	    (u->u.status.callstate.state == UNI_CALLSTATE_REST0 &&
397122205Sharti	     uni->glob_start == UNI_CALLSTATE_REST1) ||
398122205Sharti	    (u->u.status.callstate.state == UNI_CALLSTATE_REST2 &&
399122205Sharti	     uni->glob_start == UNI_CALLSTATE_REST1)) {
400122205Sharti		/*
401122205Sharti		 * Implementation dependend procedure:
402122205Sharti		 * Inform the API
403122205Sharti		 */
404122205Sharti		struct uniapi_reset_status_indication *resp;
405122205Sharti		struct uni_msg *app;
406122205Sharti
407122205Sharti		resp = ALLOC_API(struct uniapi_reset_status_indication, app);
408122205Sharti		if (resp == NULL)
409122205Sharti			return;
410122205Sharti		resp->cref = u->u.hdr.cref;
411122205Sharti		resp->callstate = u->u.status.callstate;
412122205Sharti		if (IE_ISGOOD(u->u.status.cause))
413122205Sharti			resp->cause = u->u.status.cause;
414122205Sharti
415122205Sharti		uni->funcs->uni_output(uni, uni->arg,
416122205Sharti		    UNIAPI_RESET_STATUS_indication, 0, app);
417122205Sharti
418122205Sharti	} else {
419122205Sharti		struct uniapi_reset_error_indication *resp;
420122205Sharti		struct uni_msg *app;
421122205Sharti
422122205Sharti		resp = ALLOC_API(struct uniapi_reset_error_indication, app);
423122205Sharti		if (resp != NULL) {
424122205Sharti			resp->source = 0;
425122205Sharti			resp->reason = UNIAPI_RESET_ERROR_PEER_INCOMP_STATE,
426122205Sharti
427122205Sharti			uni->funcs->uni_output(uni, uni->arg,
428122205Sharti			    UNIAPI_RESET_ERROR_indication, 0, app);
429122205Sharti		}
430122205Sharti	}
431122205Sharti}
432122205Sharti
433122205Sharti/************************************************************/
434122205Sharti/*
435122205Sharti * Reset-Respond process.
436122205Sharti */
437122205Shartivoid
438131826Shartiuni_sig_respond(struct uni *uni, u_int sig, uint32_t cookie,
439122205Sharti    struct uni_msg *m, struct uni_all *u)
440122205Sharti{
441122205Sharti	if (sig >= SIGR_END) {
442122205Sharti		VERBOSE(uni, UNI_FAC_ERR, 1, "Signal %d outside of range to "
443122205Sharti		    "Reset-Respond", sig);
444122205Sharti		if (m)
445122205Sharti			uni_msg_destroy(m);
446122205Sharti		if (u)
447122205Sharti			UNI_FREE(u);
448122205Sharti		return;
449122205Sharti	}
450122205Sharti
451122205Sharti	VERBOSE(uni, UNI_FAC_RESTART, 1,
452122205Sharti	    "Signal %s in state %u of Reset-Respond; cookie %u",
453122205Sharti	    respond_sigs[sig], uni->glob_respond, cookie);
454122205Sharti
455122205Sharti	switch (sig) {
456122205Sharti
457122205Sharti	/*
458122205Sharti	 * SAAL
459122205Sharti	 */
460122205Sharti	  case SIGR_RESTART:
461122205Sharti		response_restart(uni, m, u);
462122205Sharti		uni_msg_destroy(m);
463122205Sharti		UNI_FREE(u);
464122205Sharti		break;
465122205Sharti
466122205Sharti	  case SIGR_STATUS:
467122205Sharti		response_status(uni, m, u);
468122205Sharti		uni_msg_destroy(m);
469122205Sharti		UNI_FREE(u);
470122205Sharti		break;
471122205Sharti
472122205Sharti	/*
473122205Sharti	 * User
474122205Sharti	 */
475122205Sharti	  case SIGR_RESET_ERROR_response:
476122205Sharti		response_error(uni,
477122205Sharti		    uni_msg_rptr(m, struct uniapi_reset_error_response *),
478122205Sharti		    cookie);
479122205Sharti		uni_msg_destroy(m);
480122205Sharti		break;
481122205Sharti
482122205Sharti	  case SIGR_RESET_response:
483122205Sharti		response_response(uni,
484122205Sharti		    uni_msg_rptr(m, struct uniapi_reset_response *), cookie);
485122205Sharti		uni_msg_destroy(m);
486122205Sharti		break;
487122205Sharti
488122205Sharti	/*
489122205Sharti	 * Timers
490122205Sharti	 */
491122205Sharti	  case SIGR_T317:
492122205Sharti		response_t317(uni);
493122205Sharti		return;
494122205Sharti
495122205Sharti	  case SIGR_END:
496122205Sharti		break;
497122205Sharti	}
498122205Sharti}
499122205Sharti
500122205Sharti/*
501122205Sharti * Send a RELEASE_COMPLETE to all affected calls as per
502122205Sharti * F.2.3(3)
503122205Sharti */
504122205Shartistatic int
505122205Shartirestart_forward(struct uni *uni, const struct uni_all *u)
506122205Sharti{
507122205Sharti	struct call *c;
508122205Sharti	struct uni_all *resp;
509122205Sharti
510122205Sharti	if ((resp = UNI_ALLOC()) == NULL)
511122205Sharti		return (-1);
512122205Sharti
513122205Sharti	TAILQ_FOREACH(c, &uni->calls, link) {
514122205Sharti		if (u->u.restart.restart.rclass == UNI_RESTART_ALL ||
515122205Sharti		    (IE_ISPRESENT(c->connid) &&
516122205Sharti		    u->u.restart.connid.vpci == c->connid.vpci &&
517122205Sharti		    (u->u.restart.restart.rclass == UNI_RESTART_PATH ||
518122205Sharti		    u->u.restart.connid.vci == c->connid.vci))) {
519122205Sharti			MK_MSG_ORIG(resp, UNI_RELEASE_COMPL, c->cref, c->mine);
520122205Sharti			uni_release_compl(c, resp);
521122205Sharti		}
522122205Sharti	}
523122205Sharti
524122205Sharti	UNI_FREE(resp);
525122205Sharti	return (0);
526122205Sharti}
527122205Sharti
528122205Sharti/*
529122205Sharti * Respond process got a restart message.
530122205Sharti * Doesn't free the messages.
531122205Sharti */
532122205Shartistatic void
533122205Shartiresponse_restart(struct uni *uni, struct uni_msg *m, struct uni_all *u)
534122205Sharti{
535122205Sharti	struct uni_msg *app;
536122205Sharti	struct uniapi_reset_indication *ind;
537122205Sharti
538122205Sharti	if (uni->glob_respond == UNI_CALLSTATE_REST0) {
539122205Sharti		/*
540122205Sharti		 * If body decoding fails, this is because IEs are wrong.
541122205Sharti		 */
542122205Sharti		(void)uni_decode_body(m, u, &uni->cx);
543122205Sharti		MANDATE_IE(uni, u->u.restart.restart, UNI_IE_RESTART);
544122205Sharti		if (IE_ISGOOD(u->u.restart.restart)) {
545122205Sharti			/*
546122205Sharti			 * Q.2931: 5.5.2.2
547122205Sharti			 */
548122205Sharti			if (u->u.restart.restart.rclass == UNI_RESTART_ALL &&
549122205Sharti			   IE_ISGOOD(u->u.restart.connid)) {
550213789Srpaulo				(void)UNI_SAVE_IERR(&uni->cx, UNI_IE_CONNID,
551122205Sharti				    u->u.restart.connid.h.act,
552122205Sharti				    UNI_IERR_UNK);
553122205Sharti			} else if ((u->u.restart.restart.rclass == UNI_RESTART_PATH ||
554122205Sharti				   u->u.restart.restart.rclass == UNI_RESTART_CHANNEL)) {
555122205Sharti				MANDATE_IE(uni, u->u.restart.connid, UNI_IE_CONNID);
556122205Sharti			}
557122205Sharti		}
558122205Sharti		switch (uni_verify(uni, u->u.hdr.act)) {
559122205Sharti		  case VFY_RAIM:
560122205Sharti		  case VFY_RAI:
561122205Sharti			uni_respond_status_verify(uni, &u->u.hdr.cref,
562122205Sharti			    UNI_CALLSTATE_REST0, NULL, 0);
563122205Sharti		  case VFY_CLR:
564122205Sharti		  case VFY_I:
565122205Sharti			return;
566122205Sharti
567122205Sharti		  case VFY_RAP:
568122205Sharti		  case VFY_RAPU:
569122205Sharti			uni_respond_status_verify(uni, &u->u.hdr.cref,
570122205Sharti			    UNI_CALLSTATE_REST2, NULL, 0);
571122205Sharti		  case VFY_OK:
572122205Sharti			break;
573122205Sharti		}
574122205Sharti		if (!IE_ISGOOD(u->u.restart.connid))
575122205Sharti			u->u.restart.connid.h.present = 0;
576122205Sharti
577122205Sharti		/*
578122205Sharti		 * Send a RELEASE_COMPLETE to all affected calls as per
579122205Sharti		 * F.2.3(3)
580122205Sharti		 */
581122205Sharti		if (restart_forward(uni, u))
582122205Sharti			return;
583122205Sharti
584122205Sharti		/*
585122205Sharti		 * Build restart signal for application
586122205Sharti		 */
587122205Sharti		if ((ind = ALLOC_API(struct uniapi_reset_indication, app)) == NULL)
588122205Sharti			return;
589122205Sharti
590122205Sharti		ind->restart = u->u.restart.restart;
591122205Sharti		ind->connid = u->u.restart.connid;
592122205Sharti
593122205Sharti		uni_enq_coord(uni, SIGO_RESET_indication, 0, app);
594122205Sharti
595122205Sharti		TIMER_START_UNI(uni, t317, uni->timer317);
596122205Sharti		uni->glob_respond = UNI_CALLSTATE_REST2;
597122205Sharti
598122205Sharti		VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond state := 2");
599122205Sharti
600122205Sharti
601122205Sharti	} else if (uni->glob_respond == UNI_CALLSTATE_REST2) {
602122205Sharti		/*
603122205Sharti		 * No need to decode the message. It is unexpected in this
604122205Sharti		 * state so return a status.
605122205Sharti		 */
606122205Sharti		uni_respond_status_mtype(uni, &u->u.hdr.cref, uni->glob_respond,
607122205Sharti		    UNI_CAUSE_MSG_INCOMP, UNI_RESTART);
608122205Sharti
609122205Sharti
610122205Sharti	} else
611122205Sharti		ASSERT(0, ("bad global call state in responder"));
612122205Sharti}
613122205Sharti
614122205Shartistatic void
615122205Shartiresponse_t317(struct uni *uni)
616122205Sharti{
617122205Sharti	struct uniapi_reset_error_indication *resp;
618122205Sharti	struct uni_msg *app;
619122205Sharti
620122205Sharti	if (uni->glob_respond != UNI_CALLSTATE_REST2) {
621122205Sharti		VERBOSE0(uni, UNI_FAC_ERR, "T317 in state %d",
622122205Sharti		    uni->glob_respond);
623122205Sharti		return;
624122205Sharti	}
625122205Sharti
626122205Sharti	VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond error");
627122205Sharti
628122205Sharti	if ((resp = ALLOC_API(struct uniapi_reset_error_indication, app)) != NULL) {
629122205Sharti		resp->source = 1;
630122205Sharti		resp->reason = UNIAPI_RESET_ERROR_NO_CONFIRM;
631122205Sharti
632122205Sharti		uni->funcs->uni_output(uni, uni->arg,
633122205Sharti		    UNIAPI_RESET_ERROR_indication, 0, app);
634122205Sharti	}
635122205Sharti
636122205Sharti	uni->glob_respond = UNI_CALLSTATE_REST0;
637122205Sharti	VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond state := 0");
638122205Sharti}
639122205Sharti
640122205Sharti/*
641122205Sharti * Error response from USER
642122205Sharti */
643122205Shartistatic void
644122205Shartiresponse_error(struct uni *uni, struct uniapi_reset_error_response *c,
645131826Sharti    uint32_t cookie)
646122205Sharti{
647122205Sharti	struct uni_all *resp;
648122205Sharti
649122205Sharti	if (uni->glob_respond != UNI_CALLSTATE_REST2) {
650122205Sharti		uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0);
651122205Sharti		return;
652122205Sharti	}
653122205Sharti
654122205Sharti	if ((resp = UNI_ALLOC()) == NULL) {
655122205Sharti		uniapi_uni_error(uni, UNIAPI_ERROR_NOMEM, cookie, 0);
656122205Sharti		return;
657122205Sharti	}
658122205Sharti
659122205Sharti	MK_MSG_ORIG(resp, UNI_STATUS, 0, 1);
660122205Sharti	MK_IE_CALLSTATE(resp->u.status.callstate, UNI_CALLSTATE_REST2);
661122205Sharti
662122205Sharti	if (IE_ISGOOD(c->cause))
663122205Sharti		resp->u.status.cause = c->cause;
664122205Sharti	else {
665122205Sharti		MK_IE_CAUSE(resp->u.status.cause, UNI_CAUSE_LOC_USER,
666122205Sharti		    UNI_CAUSE_CHANNEL_NEX);
667122205Sharti		if (IE_ISGOOD(uni->connid_respond))
668122205Sharti			ADD_CAUSE_CHANNID(resp->u.status.cause,
669122205Sharti			    uni->connid_respond.vpci,
670122205Sharti			    uni->connid_respond.vci);
671122205Sharti	}
672122205Sharti
673122205Sharti	if (uni_send_output(resp, uni) != 0) {
674122205Sharti		uniapi_uni_error(uni, UNIAPI_ERROR_ENCODING, cookie, 0);
675122205Sharti		UNI_FREE(resp);
676122205Sharti		return;
677122205Sharti	}
678122205Sharti
679122205Sharti	uniapi_uni_error(uni, UNIAPI_OK, cookie, 0);
680122205Sharti}
681122205Sharti
682122205Sharti/*
683122205Sharti * Reset-response from user.
684122205Sharti */
685122205Shartistatic void
686122205Shartiresponse_response(struct uni *uni, struct uniapi_reset_response *arg,
687131826Sharti    uint32_t cookie)
688122205Sharti{
689122205Sharti	struct uni_all *resp;
690122205Sharti
691122205Sharti	if (uni->glob_respond != UNI_CALLSTATE_REST2) {
692122205Sharti		uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0);
693122205Sharti		return;
694122205Sharti	}
695122205Sharti
696122205Sharti	if (!IE_ISGOOD(arg->restart)) {
697122205Sharti		uniapi_uni_error(uni, UNIAPI_ERROR_MISSING_IE, cookie, 0);
698122205Sharti		return;
699122205Sharti	}
700122205Sharti
701122205Sharti	if ((resp = UNI_ALLOC()) == NULL) {
702122205Sharti		uniapi_uni_error(uni, UNIAPI_ERROR_NOMEM, cookie, 0);
703122205Sharti		return;
704122205Sharti	}
705122205Sharti
706122205Sharti	TIMER_STOP_UNI(uni, t317);
707122205Sharti
708122205Sharti	MK_MSG_ORIG(resp, UNI_RESTART_ACK, 0, 1);
709122205Sharti	resp->u.restart.restart = arg->restart;
710122205Sharti	if (IE_ISGOOD(arg->connid))
711122205Sharti		resp->u.restart.connid = arg->connid;
712122205Sharti
713122205Sharti	if (uni_send_output(resp, uni) != 0) {
714122205Sharti		uniapi_uni_error(uni, UNIAPI_ERROR_ENCODING, cookie, 0);
715122205Sharti		UNI_FREE(resp);
716122205Sharti		return;
717122205Sharti	}
718122205Sharti
719122205Sharti	UNI_FREE(resp);
720122205Sharti
721122205Sharti	uni->glob_respond = UNI_CALLSTATE_REST0;
722122205Sharti	VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond state := 0");
723122205Sharti
724122205Sharti	uniapi_uni_error(uni, UNIAPI_OK, cookie, 0);
725122205Sharti}
726122205Sharti
727122205Sharti/*
728122205Sharti * Reset-Response got a STATUS message.
729122205Sharti *
730122205Sharti * Q.2931: Reset-Response 2/2
731122205Sharti *
732122205Sharti * In Q.2931 only CALLSTATE_REST2 is allowed, this seems silly and to contradict
733122205Sharti * 5.6.12. So allow it in any state.
734122205Sharti *
735122205Sharti * The following states are considered compatible:
736122205Sharti *
737122205Sharti *  Sender   Receiver
738122205Sharti *  ------   --------
739122205Sharti *  Rest0     Rest0	this is the normal state OK!
740122205Sharti *  Rest0     Rest2	this may be the result of no answer from the API
741122205Sharti *			and the Sender finally timing out. ERROR!
742122205Sharti *  Rest1     Rest2	this is normal. OK!
743122205Sharti *  Rest1     Rest0	RESTART_ACK was probably lost. OK!
744122205Sharti *
745122205Sharti * All others are wrong.
746122205Sharti */
747122205Shartistatic void
748122205Shartiresponse_status(struct uni *uni, struct uni_msg *m, struct uni_all *u)
749122205Sharti{
750122205Sharti	(void)uni_decode_body(m, u, &uni->cx);
751122205Sharti	MANDATE_IE(uni, u->u.status.callstate, UNI_IE_CALLSTATE);
752122205Sharti	MANDATE_IE(uni, u->u.status.cause, UNI_IE_CAUSE);
753122205Sharti	switch (uni_verify(uni, u->u.hdr.act)) {
754122205Sharti	  case VFY_CLR:
755122205Sharti		if (uni->proto == UNIPROTO_UNI40U) {
756122205Sharti			uni->glob_respond = UNI_CALLSTATE_REST0;
757122205Sharti			VERBOSE(uni, UNI_FAC_RESTART, 1,
758122205Sharti			    "Reset-Respond state := 0");
759122205Sharti			return;
760122205Sharti		}
761122205Sharti		break;
762122205Sharti
763122205Sharti	  case VFY_RAIM:
764122205Sharti	  case VFY_RAI:
765122205Sharti	  case VFY_RAP:
766122205Sharti	  case VFY_RAPU:
767122205Sharti		uni_respond_status_verify(uni, &u->u.hdr.cref,
768122205Sharti		    uni->glob_respond, NULL, 0);
769122205Sharti	  case VFY_I:
770122205Sharti	  case VFY_OK:
771122205Sharti		break;
772122205Sharti	}
773122205Sharti	if (!IE_ISGOOD(u->u.status.callstate)) {
774122205Sharti		/*
775122205Sharti		 * As a result of the strange handling above, we must
776122205Sharti		 * process a STATUS with an invalid or missing callstate!
777122205Sharti		 */
778122205Sharti		return;
779122205Sharti	}
780122205Sharti	if ((u->u.status.callstate.state == UNI_CALLSTATE_REST0 &&
781122205Sharti	     uni->glob_respond == UNI_CALLSTATE_REST0) ||
782122205Sharti	    (u->u.status.callstate.state == UNI_CALLSTATE_REST1 &&
783122205Sharti	     uni->glob_respond == UNI_CALLSTATE_REST0) ||
784122205Sharti	    (u->u.status.callstate.state == UNI_CALLSTATE_REST1 &&
785122205Sharti	     uni->glob_respond == UNI_CALLSTATE_REST2)) {
786122205Sharti		/*
787122205Sharti		 * Implementation dependend procedure:
788122205Sharti		 * Inform the API
789122205Sharti		 */
790122205Sharti		struct uniapi_reset_status_indication *resp;
791122205Sharti		struct uni_msg *app;
792122205Sharti
793122205Sharti		resp = ALLOC_API(struct uniapi_reset_status_indication, app);
794122205Sharti		if (resp == NULL)
795122205Sharti			return;
796122205Sharti
797122205Sharti		resp->cref = u->u.hdr.cref;
798122205Sharti		resp->callstate = u->u.status.callstate;
799122205Sharti		if (IE_ISGOOD(u->u.status.cause))
800122205Sharti			resp->cause = u->u.status.cause;
801122205Sharti
802122205Sharti		uni->funcs->uni_output(uni, uni->arg,
803122205Sharti		    UNIAPI_RESET_STATUS_indication, 0, app);
804122205Sharti
805122205Sharti	} else {
806122205Sharti		struct uniapi_reset_error_indication *resp;
807122205Sharti		struct uni_msg *app;
808122205Sharti
809122205Sharti		resp = ALLOC_API(struct uniapi_reset_error_indication, app);
810122205Sharti		if (resp != NULL) {
811122205Sharti			resp->source = 1;
812122205Sharti			resp->reason = UNIAPI_RESET_ERROR_PEER_INCOMP_STATE,
813122205Sharti
814122205Sharti			uni->funcs->uni_output(uni, uni->arg,
815122205Sharti			    UNIAPI_RESET_ERROR_indication, 0, app);
816122205Sharti		}
817122205Sharti	}
818122205Sharti}
819122205Sharti
820122205Sharti/*
821122205Sharti * T317 timeout function
822122205Sharti */
823122205Shartistatic void
824122205Shartit317_func(struct uni *uni)
825122205Sharti{
826122205Sharti	uni_enq_resp(uni, SIGR_T317, 0, NULL, NULL);
827122205Sharti}
828