sig_reset.c revision 122205
1/*
2 * Copyright (c) 1996-2003
3 *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4 * 	All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * Author: Hartmut Brandt <harti@freebsd.org>
28 *
29 * $Begemot: libunimsg/atm/sig/sig_reset.c,v 1.5 2003/09/24 10:27:50 hbb Exp $
30 *
31 * Reset-start and reset-respond
32 */
33
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>
39
40#include <netnatm/sig/unipriv.h>
41#include <netnatm/sig/unimkmsg.h>
42
43static void response_restart(struct uni *, struct uni_msg *, struct uni_all *);
44static void response_status(struct uni *, struct uni_msg *, struct uni_all *);
45
46static void response_t317(struct uni *);
47
48static void response_error(struct uni *, struct uniapi_reset_error_response *, u_int32_t cookie);
49static void response_response(struct uni *, struct uniapi_reset_response *, u_int32_t);
50
51static void start_request(struct uni *, struct uniapi_reset_request *, u_int32_t);
52
53static void start_t316(struct uni *);
54
55static void start_restart_ack(struct uni *, struct uni_msg *, struct uni_all *);
56static void start_status(struct uni *, struct uni_msg *, struct uni_all *);
57
58static int restart_forward(struct uni *, const struct uni_all *);
59
60#define DEF_PRIV_SIG(NAME, FROM)	[SIG##NAME]	"SIG"#NAME,
61static const char *const start_sigs[] = {
62	DEF_START_SIGS
63};
64#undef DEF_PRIV_SIG
65
66#define DEF_PRIV_SIG(NAME, FROM)	[SIG##NAME]	"SIG"#NAME,
67static const char *const respond_sigs[] = {
68	DEF_RESPOND_SIGS
69};
70#undef DEF_PRIV_SIG
71
72TIMER_FUNC_UNI(t317, t317_func)
73TIMER_FUNC_UNI(t316, t316_func)
74
75/*
76 * Reset-Start process.
77 */
78void
79uni_sig_start(struct uni *uni, u_int sig, u_int32_t cookie,
80    struct uni_msg *m, struct uni_all *u)
81{
82	if (sig >= SIGS_END) {
83		VERBOSE(uni, UNI_FAC_ERR, 1, "Signal %d outside of range to "
84		    "Reset-Start", sig);
85		if (m)
86			uni_msg_destroy(m);
87		if (u)
88			UNI_FREE(u);
89		return;
90	}
91
92	VERBOSE(uni, UNI_FAC_RESTART, 1,
93	    "Signal %s in state %u of Reset-Start; cookie %u",
94	    start_sigs[sig], uni->glob_start, cookie);
95
96	switch (sig) {
97
98	/*
99	 * User requests
100	 */
101	  case SIGS_RESET_request:
102		start_request(uni,
103		    uni_msg_rptr(m, struct uniapi_reset_request *), cookie);
104		uni_msg_destroy(m);
105		break;
106
107	/*
108	 * Timers
109	 */
110	  case SIGS_T316:
111		start_t316(uni);
112		break;
113
114	/*
115	 * SAAL
116	 */
117	  case SIGS_RESTART_ACK:
118		start_restart_ack(uni, m, u);
119		uni_msg_destroy(m);
120		UNI_FREE(u);
121		break;
122
123	  case SIGS_STATUS:
124		start_status(uni, m, u);
125		uni_msg_destroy(m);
126		UNI_FREE(u);
127		break;
128
129	  case SIGS_END:
130		break;
131	}
132}
133
134/*
135 * Reset-request from USER.
136 *
137 * Q.2931:Reset-Start 1/2
138 */
139static void
140start_request(struct uni *uni, struct uniapi_reset_request *req, u_int32_t cookie)
141{
142	struct uni_all *resp;
143	int err;
144
145	if (uni->glob_start != UNI_CALLSTATE_REST0) {
146		uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0);
147		return;
148	}
149
150	if ((resp = UNI_ALLOC()) == NULL) {
151		uniapi_uni_error(uni, UNIAPI_ERROR_NOMEM, cookie, 0);
152		return;
153	}
154
155	MK_MSG_ORIG(resp, UNI_RESTART, 0, 0);
156	resp->u.restart.restart = req->restart;
157	resp->u.restart.connid = req->connid;
158
159	if (restart_forward(uni, resp))
160		return;
161
162	uni->connid_start = req->connid;
163	uni->restart_start = req->restart;
164
165	if ((err = uni_send_output(resp, uni)) != 0)
166		uniapi_uni_error(uni, UNIAPI_ERROR_ENCODING, cookie, 0);
167	UNI_FREE(resp);
168	if (err)
169		return;
170
171	uni->cnt316 = 0;
172	TIMER_START_UNI(uni, t316, uni->timer316);
173	uni->glob_start = UNI_CALLSTATE_REST1;
174
175	VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 1");
176
177
178	uniapi_uni_error(uni, UNIAPI_OK, cookie, 0);
179}
180
181/*
182 * T316 timeout function
183 */
184static void
185t316_func(struct uni *uni)
186{
187	uni_enq_start(uni, SIGS_T316, 0, NULL, NULL);
188}
189
190/*
191 * Q.2931:Reset-Start 1/2
192 */
193static void
194start_t316(struct uni *uni)
195{
196	if (uni->glob_start != UNI_CALLSTATE_REST1) {
197		VERBOSE0(uni, UNI_FAC_ERR, "T316 in state %d",
198		    uni->glob_start);
199		return;
200	}
201
202	if (++uni->cnt316 == uni->init316) {
203		struct uni_msg *app;
204		struct uniapi_reset_error_indication *resp;
205
206		VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start error");
207
208		resp = ALLOC_API(struct uniapi_reset_error_indication, app);
209		if (resp != NULL) {
210			resp->source = 0;
211			resp->reason = UNIAPI_RESET_ERROR_NO_RESPONSE,
212
213			uni->funcs->uni_output(uni, uni->arg,
214			    UNIAPI_RESET_ERROR_indication, 0, app);
215		}
216
217		uni->glob_start = UNI_CALLSTATE_REST0;
218		VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 0");
219	} else {
220		struct uni_all *resp;
221
222		if ((resp = UNI_ALLOC()) == NULL)
223			return;
224
225		MK_MSG_ORIG(resp, UNI_RESTART, 0, 0);
226		resp->u.restart.restart = uni->restart_start;
227		resp->u.restart.connid = uni->connid_start;
228
229		(void)uni_send_output(resp, uni);
230
231		UNI_FREE(resp);
232
233		TIMER_START_UNI(uni, t316, uni->timer316);
234	}
235}
236
237/*
238 * Got RESTART_ACK.
239 */
240static void
241start_restart_ack(struct uni *uni, struct uni_msg *m, struct uni_all *u)
242{
243	enum uni_callstate new_state;
244	struct uniapi_reset_confirm *conf;
245	struct uni_msg *app;
246
247	if (uni->glob_start == UNI_CALLSTATE_REST0) {
248		uni_respond_status_mtype(uni, &u->u.hdr.cref, uni->glob_start,
249		    UNI_CAUSE_MSG_INCOMP, UNI_RESTART_ACK);
250		return;
251	}
252
253	if (uni->glob_start != UNI_CALLSTATE_REST1) {
254		ASSERT(0, ("bad global call state in Reset-Start"));
255		return;
256	}
257
258	/*
259	 * If body decoding fails, this is because IEs are wrong.
260	 */
261	(void)uni_decode_body(m, u, &uni->cx);
262	MANDATE_IE(uni, u->u.restart_ack.restart, UNI_IE_RESTART);
263
264	if (IE_ISGOOD(u->u.restart_ack.restart)) {
265		/*
266		 * Q.2931: 5.5.2.2
267		 */
268		if (u->u.restart_ack.restart.rclass == UNI_RESTART_ALL &&
269		    IE_ISGOOD(u->u.restart_ack.connid)) {
270			UNI_SAVE_IERR(&uni->cx, UNI_IE_CONNID,
271			    u->u.restart_ack.connid.h.act,
272			    UNI_IERR_UNK);
273		} else if ((u->u.restart_ack.restart.rclass == UNI_RESTART_PATH ||
274			    u->u.restart_ack.restart.rclass == UNI_RESTART_CHANNEL)) {
275			MANDATE_IE(uni, u->u.restart_ack.connid, UNI_IE_CONNID);
276		}
277	}
278	/*
279	 * Compare the information elements now, because
280	 * we may need the new callstate for the status message
281	 * below.
282	 */
283	new_state = UNI_CALLSTATE_REST1;
284
285	if (IE_ISGOOD(u->u.restart_ack.restart) &&
286	    IE_ISGOOD(uni->restart_start) &&
287	    u->u.restart_ack.restart.rclass == uni->restart_start.rclass &&
288	    !IE_ISGOOD(u->u.restart_ack.connid) == !IE_ISGOOD(uni->connid_start) &&
289	    (!IE_ISGOOD(uni->connid_start) ||
290	       (u->u.restart_ack.connid.vpci == uni->connid_start.vpci &&
291	        u->u.restart_ack.connid.vci == uni->connid_start.vci)))
292		new_state = UNI_CALLSTATE_REST0;
293
294	switch (uni_verify(uni, u->u.hdr.act)) {
295	  case VFY_RAIM:
296	  case VFY_RAI:
297		uni_respond_status_verify(uni, &u->u.hdr.cref,
298		    UNI_CALLSTATE_REST1, NULL, 0);
299	  case VFY_I:
300		return;
301
302	  case VFY_CLR:
303		uni->glob_start = UNI_CALLSTATE_REST0;
304		VERBOSE(uni, UNI_FAC_RESTART, 1,
305		    "Reset-Start state := 0");
306		return;
307
308	  case VFY_RAP:
309	  case VFY_RAPU:
310		uni_respond_status_verify(uni, &u->u.hdr.cref,
311		    new_state, NULL, 0);
312	  case VFY_OK:
313		break;
314	}
315
316	if (new_state == UNI_CALLSTATE_REST1)
317		/*
318		 * Q.2931: 5.5.1.2/2
319		 */
320		return;
321
322	/*
323	 * Build restart.confirm signal for application
324	 */
325	if (!IE_ISGOOD(u->u.restart_ack.connid))
326		u->u.restart.connid.h.present = 0;
327
328
329	if ((conf = ALLOC_API(struct uniapi_reset_confirm, app)) == NULL)
330		return;
331	conf->restart = u->u.restart.restart;
332	conf->connid = u->u.restart.connid;
333
334	TIMER_STOP_UNI(uni, t316);
335
336	uni->funcs->uni_output(uni, uni->arg, UNIAPI_RESET_confirm, 0, app);
337
338	uni->glob_start = UNI_CALLSTATE_REST0;
339	VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 0");
340}
341
342/*
343 * Reset-Start got a STATUS message.
344 *
345 * Q.2931: Reset-Start 2/2
346 *
347 * In Q.2931 only CALLSTATE_REST1 is allowed, this seems silly and to contradict
348 * 5.6.12. So allow it in any state.
349 *
350 * The following states are considered compatible:
351 *
352 *  Sender   Receiver(we)
353 *  ------   --------
354 *  Rest0     Rest0	this is the normal state OK!
355 *  Rest2     Rest0	this may be the result of no answer from the API
356 *			on the remote end and the us finally timing out. ERROR!
357 *  Rest2     Rest1	this is normal. OK!
358 *  Rest0     Rest1	RESTART_ACK was probably lost. OK!
359 *
360 * All others are wrong.
361 */
362static void
363start_status(struct uni *uni, struct uni_msg *m, struct uni_all *u)
364{
365	(void)uni_decode_body(m, u, &uni->cx);
366	MANDATE_IE(uni, u->u.status.callstate, UNI_IE_CALLSTATE);
367	MANDATE_IE(uni, u->u.status.cause, UNI_IE_CAUSE);
368	switch (uni_verify(uni, u->u.hdr.act)) {
369	  case VFY_CLR:
370		uni->glob_start = UNI_CALLSTATE_REST0;
371		VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 0");
372		return;
373
374	  case VFY_RAIM:
375	  case VFY_RAI:
376	  case VFY_RAP:
377	  case VFY_RAPU:
378		uni_respond_status_verify(uni, &u->u.hdr.cref, uni->glob_start,
379		    NULL, 0);
380	  case VFY_I:
381	  case VFY_OK:
382		break;
383	}
384	if (!IE_ISGOOD(u->u.status.callstate)) {
385		/*
386		 * As a result of the strange handling above, we must
387		 * process a STATUS with an invalid or missing callstate!
388		 */
389		return;
390	}
391	if ((u->u.status.callstate.state == UNI_CALLSTATE_REST0 &&
392	     uni->glob_start == UNI_CALLSTATE_REST0) ||
393	    (u->u.status.callstate.state == UNI_CALLSTATE_REST0 &&
394	     uni->glob_start == UNI_CALLSTATE_REST1) ||
395	    (u->u.status.callstate.state == UNI_CALLSTATE_REST2 &&
396	     uni->glob_start == UNI_CALLSTATE_REST1)) {
397		/*
398		 * Implementation dependend procedure:
399		 * Inform the API
400		 */
401		struct uniapi_reset_status_indication *resp;
402		struct uni_msg *app;
403
404		resp = ALLOC_API(struct uniapi_reset_status_indication, app);
405		if (resp == NULL)
406			return;
407		resp->cref = u->u.hdr.cref;
408		resp->callstate = u->u.status.callstate;
409		if (IE_ISGOOD(u->u.status.cause))
410			resp->cause = u->u.status.cause;
411
412		uni->funcs->uni_output(uni, uni->arg,
413		    UNIAPI_RESET_STATUS_indication, 0, app);
414
415	} else {
416		struct uniapi_reset_error_indication *resp;
417		struct uni_msg *app;
418
419		resp = ALLOC_API(struct uniapi_reset_error_indication, app);
420		if (resp != NULL) {
421			resp->source = 0;
422			resp->reason = UNIAPI_RESET_ERROR_PEER_INCOMP_STATE,
423
424			uni->funcs->uni_output(uni, uni->arg,
425			    UNIAPI_RESET_ERROR_indication, 0, app);
426		}
427	}
428}
429
430/************************************************************/
431/*
432 * Reset-Respond process.
433 */
434void
435uni_sig_respond(struct uni *uni, u_int sig, u_int32_t cookie,
436    struct uni_msg *m, struct uni_all *u)
437{
438	if (sig >= SIGR_END) {
439		VERBOSE(uni, UNI_FAC_ERR, 1, "Signal %d outside of range to "
440		    "Reset-Respond", sig);
441		if (m)
442			uni_msg_destroy(m);
443		if (u)
444			UNI_FREE(u);
445		return;
446	}
447
448	VERBOSE(uni, UNI_FAC_RESTART, 1,
449	    "Signal %s in state %u of Reset-Respond; cookie %u",
450	    respond_sigs[sig], uni->glob_respond, cookie);
451
452	switch (sig) {
453
454	/*
455	 * SAAL
456	 */
457	  case SIGR_RESTART:
458		response_restart(uni, m, u);
459		uni_msg_destroy(m);
460		UNI_FREE(u);
461		break;
462
463	  case SIGR_STATUS:
464		response_status(uni, m, u);
465		uni_msg_destroy(m);
466		UNI_FREE(u);
467		break;
468
469	/*
470	 * User
471	 */
472	  case SIGR_RESET_ERROR_response:
473		response_error(uni,
474		    uni_msg_rptr(m, struct uniapi_reset_error_response *),
475		    cookie);
476		uni_msg_destroy(m);
477		break;
478
479	  case SIGR_RESET_response:
480		response_response(uni,
481		    uni_msg_rptr(m, struct uniapi_reset_response *), cookie);
482		uni_msg_destroy(m);
483		break;
484
485	/*
486	 * Timers
487	 */
488	  case SIGR_T317:
489		response_t317(uni);
490		return;
491
492	  case SIGR_END:
493		break;
494	}
495}
496
497/*
498 * Send a RELEASE_COMPLETE to all affected calls as per
499 * F.2.3(3)
500 */
501static int
502restart_forward(struct uni *uni, const struct uni_all *u)
503{
504	struct call *c;
505	struct uni_all *resp;
506
507	if ((resp = UNI_ALLOC()) == NULL)
508		return (-1);
509
510	TAILQ_FOREACH(c, &uni->calls, link) {
511		if (u->u.restart.restart.rclass == UNI_RESTART_ALL ||
512		    (IE_ISPRESENT(c->connid) &&
513		    u->u.restart.connid.vpci == c->connid.vpci &&
514		    (u->u.restart.restart.rclass == UNI_RESTART_PATH ||
515		    u->u.restart.connid.vci == c->connid.vci))) {
516			MK_MSG_ORIG(resp, UNI_RELEASE_COMPL, c->cref, c->mine);
517			uni_release_compl(c, resp);
518		}
519	}
520
521	UNI_FREE(resp);
522	return (0);
523}
524
525/*
526 * Respond process got a restart message.
527 * Doesn't free the messages.
528 */
529static void
530response_restart(struct uni *uni, struct uni_msg *m, struct uni_all *u)
531{
532	struct uni_msg *app;
533	struct uniapi_reset_indication *ind;
534
535	if (uni->glob_respond == UNI_CALLSTATE_REST0) {
536		/*
537		 * If body decoding fails, this is because IEs are wrong.
538		 */
539		(void)uni_decode_body(m, u, &uni->cx);
540		MANDATE_IE(uni, u->u.restart.restart, UNI_IE_RESTART);
541		if (IE_ISGOOD(u->u.restart.restart)) {
542			/*
543			 * Q.2931: 5.5.2.2
544			 */
545			if (u->u.restart.restart.rclass == UNI_RESTART_ALL &&
546			   IE_ISGOOD(u->u.restart.connid)) {
547				UNI_SAVE_IERR(&uni->cx, UNI_IE_CONNID,
548				    u->u.restart.connid.h.act,
549				    UNI_IERR_UNK);
550			} else if ((u->u.restart.restart.rclass == UNI_RESTART_PATH ||
551				   u->u.restart.restart.rclass == UNI_RESTART_CHANNEL)) {
552				MANDATE_IE(uni, u->u.restart.connid, UNI_IE_CONNID);
553			}
554		}
555		switch (uni_verify(uni, u->u.hdr.act)) {
556		  case VFY_RAIM:
557		  case VFY_RAI:
558			uni_respond_status_verify(uni, &u->u.hdr.cref,
559			    UNI_CALLSTATE_REST0, NULL, 0);
560		  case VFY_CLR:
561		  case VFY_I:
562			return;
563
564		  case VFY_RAP:
565		  case VFY_RAPU:
566			uni_respond_status_verify(uni, &u->u.hdr.cref,
567			    UNI_CALLSTATE_REST2, NULL, 0);
568		  case VFY_OK:
569			break;
570		}
571		if (!IE_ISGOOD(u->u.restart.connid))
572			u->u.restart.connid.h.present = 0;
573
574		/*
575		 * Send a RELEASE_COMPLETE to all affected calls as per
576		 * F.2.3(3)
577		 */
578		if (restart_forward(uni, u))
579			return;
580
581		/*
582		 * Build restart signal for application
583		 */
584		if ((ind = ALLOC_API(struct uniapi_reset_indication, app)) == NULL)
585			return;
586
587		ind->restart = u->u.restart.restart;
588		ind->connid = u->u.restart.connid;
589
590		uni_enq_coord(uni, SIGO_RESET_indication, 0, app);
591
592		TIMER_START_UNI(uni, t317, uni->timer317);
593		uni->glob_respond = UNI_CALLSTATE_REST2;
594
595		VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond state := 2");
596
597
598	} else if (uni->glob_respond == UNI_CALLSTATE_REST2) {
599		/*
600		 * No need to decode the message. It is unexpected in this
601		 * state so return a status.
602		 */
603		uni_respond_status_mtype(uni, &u->u.hdr.cref, uni->glob_respond,
604		    UNI_CAUSE_MSG_INCOMP, UNI_RESTART);
605
606
607	} else
608		ASSERT(0, ("bad global call state in responder"));
609}
610
611static void
612response_t317(struct uni *uni)
613{
614	struct uniapi_reset_error_indication *resp;
615	struct uni_msg *app;
616
617	if (uni->glob_respond != UNI_CALLSTATE_REST2) {
618		VERBOSE0(uni, UNI_FAC_ERR, "T317 in state %d",
619		    uni->glob_respond);
620		return;
621	}
622
623	VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond error");
624
625	if ((resp = ALLOC_API(struct uniapi_reset_error_indication, app)) != NULL) {
626		resp->source = 1;
627		resp->reason = UNIAPI_RESET_ERROR_NO_CONFIRM;
628
629		uni->funcs->uni_output(uni, uni->arg,
630		    UNIAPI_RESET_ERROR_indication, 0, app);
631	}
632
633	uni->glob_respond = UNI_CALLSTATE_REST0;
634	VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond state := 0");
635}
636
637/*
638 * Error response from USER
639 */
640static void
641response_error(struct uni *uni, struct uniapi_reset_error_response *c,
642    u_int32_t cookie)
643{
644	struct uni_all *resp;
645
646	if (uni->glob_respond != UNI_CALLSTATE_REST2) {
647		uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0);
648		return;
649	}
650
651	if ((resp = UNI_ALLOC()) == NULL) {
652		uniapi_uni_error(uni, UNIAPI_ERROR_NOMEM, cookie, 0);
653		return;
654	}
655
656	MK_MSG_ORIG(resp, UNI_STATUS, 0, 1);
657	MK_IE_CALLSTATE(resp->u.status.callstate, UNI_CALLSTATE_REST2);
658
659	if (IE_ISGOOD(c->cause))
660		resp->u.status.cause = c->cause;
661	else {
662		MK_IE_CAUSE(resp->u.status.cause, UNI_CAUSE_LOC_USER,
663		    UNI_CAUSE_CHANNEL_NEX);
664		if (IE_ISGOOD(uni->connid_respond))
665			ADD_CAUSE_CHANNID(resp->u.status.cause,
666			    uni->connid_respond.vpci,
667			    uni->connid_respond.vci);
668	}
669
670	if (uni_send_output(resp, uni) != 0) {
671		uniapi_uni_error(uni, UNIAPI_ERROR_ENCODING, cookie, 0);
672		UNI_FREE(resp);
673		return;
674	}
675
676	uniapi_uni_error(uni, UNIAPI_OK, cookie, 0);
677}
678
679/*
680 * Reset-response from user.
681 */
682static void
683response_response(struct uni *uni, struct uniapi_reset_response *arg,
684    u_int32_t cookie)
685{
686	struct uni_all *resp;
687
688	if (uni->glob_respond != UNI_CALLSTATE_REST2) {
689		uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0);
690		return;
691	}
692
693	if (!IE_ISGOOD(arg->restart)) {
694		uniapi_uni_error(uni, UNIAPI_ERROR_MISSING_IE, cookie, 0);
695		return;
696	}
697
698	if ((resp = UNI_ALLOC()) == NULL) {
699		uniapi_uni_error(uni, UNIAPI_ERROR_NOMEM, cookie, 0);
700		return;
701	}
702
703	TIMER_STOP_UNI(uni, t317);
704
705	MK_MSG_ORIG(resp, UNI_RESTART_ACK, 0, 1);
706	resp->u.restart.restart = arg->restart;
707	if (IE_ISGOOD(arg->connid))
708		resp->u.restart.connid = arg->connid;
709
710	if (uni_send_output(resp, uni) != 0) {
711		uniapi_uni_error(uni, UNIAPI_ERROR_ENCODING, cookie, 0);
712		UNI_FREE(resp);
713		return;
714	}
715
716	UNI_FREE(resp);
717
718	uni->glob_respond = UNI_CALLSTATE_REST0;
719	VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Respond state := 0");
720
721	uniapi_uni_error(uni, UNIAPI_OK, cookie, 0);
722}
723
724/*
725 * Reset-Response got a STATUS message.
726 *
727 * Q.2931: Reset-Response 2/2
728 *
729 * In Q.2931 only CALLSTATE_REST2 is allowed, this seems silly and to contradict
730 * 5.6.12. So allow it in any state.
731 *
732 * The following states are considered compatible:
733 *
734 *  Sender   Receiver
735 *  ------   --------
736 *  Rest0     Rest0	this is the normal state OK!
737 *  Rest0     Rest2	this may be the result of no answer from the API
738 *			and the Sender finally timing out. ERROR!
739 *  Rest1     Rest2	this is normal. OK!
740 *  Rest1     Rest0	RESTART_ACK was probably lost. OK!
741 *
742 * All others are wrong.
743 */
744static void
745response_status(struct uni *uni, struct uni_msg *m, struct uni_all *u)
746{
747	(void)uni_decode_body(m, u, &uni->cx);
748	MANDATE_IE(uni, u->u.status.callstate, UNI_IE_CALLSTATE);
749	MANDATE_IE(uni, u->u.status.cause, UNI_IE_CAUSE);
750	switch (uni_verify(uni, u->u.hdr.act)) {
751	  case VFY_CLR:
752		if (uni->proto == UNIPROTO_UNI40U) {
753			uni->glob_respond = UNI_CALLSTATE_REST0;
754			VERBOSE(uni, UNI_FAC_RESTART, 1,
755			    "Reset-Respond state := 0");
756			return;
757		}
758		break;
759
760	  case VFY_RAIM:
761	  case VFY_RAI:
762	  case VFY_RAP:
763	  case VFY_RAPU:
764		uni_respond_status_verify(uni, &u->u.hdr.cref,
765		    uni->glob_respond, NULL, 0);
766	  case VFY_I:
767	  case VFY_OK:
768		break;
769	}
770	if (!IE_ISGOOD(u->u.status.callstate)) {
771		/*
772		 * As a result of the strange handling above, we must
773		 * process a STATUS with an invalid or missing callstate!
774		 */
775		return;
776	}
777	if ((u->u.status.callstate.state == UNI_CALLSTATE_REST0 &&
778	     uni->glob_respond == UNI_CALLSTATE_REST0) ||
779	    (u->u.status.callstate.state == UNI_CALLSTATE_REST1 &&
780	     uni->glob_respond == UNI_CALLSTATE_REST0) ||
781	    (u->u.status.callstate.state == UNI_CALLSTATE_REST1 &&
782	     uni->glob_respond == UNI_CALLSTATE_REST2)) {
783		/*
784		 * Implementation dependend procedure:
785		 * Inform the API
786		 */
787		struct uniapi_reset_status_indication *resp;
788		struct uni_msg *app;
789
790		resp = ALLOC_API(struct uniapi_reset_status_indication, app);
791		if (resp == NULL)
792			return;
793
794		resp->cref = u->u.hdr.cref;
795		resp->callstate = u->u.status.callstate;
796		if (IE_ISGOOD(u->u.status.cause))
797			resp->cause = u->u.status.cause;
798
799		uni->funcs->uni_output(uni, uni->arg,
800		    UNIAPI_RESET_STATUS_indication, 0, app);
801
802	} else {
803		struct uniapi_reset_error_indication *resp;
804		struct uni_msg *app;
805
806		resp = ALLOC_API(struct uniapi_reset_error_indication, app);
807		if (resp != NULL) {
808			resp->source = 1;
809			resp->reason = UNIAPI_RESET_ERROR_PEER_INCOMP_STATE,
810
811			uni->funcs->uni_output(uni, uni->arg,
812			    UNIAPI_RESET_ERROR_indication, 0, app);
813		}
814	}
815}
816
817/*
818 * T317 timeout function
819 */
820static void
821t317_func(struct uni *uni)
822{
823	uni_enq_resp(uni, SIGR_T317, 0, NULL, NULL);
824}
825