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