1/*
2 * Copyright (c) 1996-2003
3 *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4 * 	All rights reserved.
5 *
6 * Author: Hartmut Brandt <harti@freebsd.org>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $Begemot: libunimsg/netnatm/sig/sig_reset.c,v 1.11 2004/08/05 07:11:03 brandt 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 *,
49    uint32_t cookie);
50static void response_response(struct uni *, struct uniapi_reset_response *,
51    uint32_t);
52
53static void start_request(struct uni *, struct uniapi_reset_request *,
54    uint32_t);
55
56static void start_t316(struct uni *);
57
58static void start_restart_ack(struct uni *, struct uni_msg *, struct uni_all *);
59static void start_status(struct uni *, struct uni_msg *, struct uni_all *);
60
61static int restart_forward(struct uni *, const struct uni_all *);
62
63#define DEF_PRIV_SIG(NAME, FROM)	[SIG##NAME] =	"SIG"#NAME,
64static const char *const start_sigs[] = {
65	DEF_START_SIGS
66};
67#undef DEF_PRIV_SIG
68
69#define DEF_PRIV_SIG(NAME, FROM)	[SIG##NAME] =	"SIG"#NAME,
70static const char *const respond_sigs[] = {
71	DEF_RESPOND_SIGS
72};
73#undef DEF_PRIV_SIG
74
75TIMER_FUNC_UNI(t317, t317_func)
76TIMER_FUNC_UNI(t316, t316_func)
77
78/*
79 * Reset-Start process.
80 */
81void
82uni_sig_start(struct uni *uni, u_int sig, uint32_t cookie,
83    struct uni_msg *m, struct uni_all *u)
84{
85	if (sig >= SIGS_END) {
86		VERBOSE(uni, UNI_FAC_ERR, 1, "Signal %d outside of range to "
87		    "Reset-Start", sig);
88		if (m)
89			uni_msg_destroy(m);
90		if (u)
91			UNI_FREE(u);
92		return;
93	}
94
95	VERBOSE(uni, UNI_FAC_RESTART, 1,
96	    "Signal %s in state %u of Reset-Start; cookie %u",
97	    start_sigs[sig], uni->glob_start, cookie);
98
99	switch (sig) {
100
101	/*
102	 * User requests
103	 */
104	  case SIGS_RESET_request:
105		start_request(uni,
106		    uni_msg_rptr(m, struct uniapi_reset_request *), cookie);
107		uni_msg_destroy(m);
108		break;
109
110	/*
111	 * Timers
112	 */
113	  case SIGS_T316:
114		start_t316(uni);
115		break;
116
117	/*
118	 * SAAL
119	 */
120	  case SIGS_RESTART_ACK:
121		start_restart_ack(uni, m, u);
122		uni_msg_destroy(m);
123		UNI_FREE(u);
124		break;
125
126	  case SIGS_STATUS:
127		start_status(uni, m, u);
128		uni_msg_destroy(m);
129		UNI_FREE(u);
130		break;
131
132	  case SIGS_END:
133		break;
134	}
135}
136
137/*
138 * Reset-request from USER.
139 *
140 * Q.2931:Reset-Start 1/2
141 */
142static void
143start_request(struct uni *uni, struct uniapi_reset_request *req, uint32_t cookie)
144{
145	struct uni_all *resp;
146	int err;
147
148	if (uni->glob_start != UNI_CALLSTATE_REST0) {
149		uniapi_uni_error(uni, UNIAPI_ERROR_BAD_CALLSTATE, cookie, 0);
150		return;
151	}
152
153	if ((resp = UNI_ALLOC()) == NULL) {
154		uniapi_uni_error(uni, UNIAPI_ERROR_NOMEM, cookie, 0);
155		return;
156	}
157
158	MK_MSG_ORIG(resp, UNI_RESTART, 0, 0);
159	resp->u.restart.restart = req->restart;
160	resp->u.restart.connid = req->connid;
161
162	if (restart_forward(uni, resp))
163		return;
164
165	uni->connid_start = req->connid;
166	uni->restart_start = req->restart;
167
168	if ((err = uni_send_output(resp, uni)) != 0)
169		uniapi_uni_error(uni, UNIAPI_ERROR_ENCODING, cookie, 0);
170	UNI_FREE(resp);
171	if (err)
172		return;
173
174	uni->cnt316 = 0;
175	TIMER_START_UNI(uni, t316, uni->timer316);
176	uni->glob_start = UNI_CALLSTATE_REST1;
177
178	VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start state := 1");
179
180
181	uniapi_uni_error(uni, UNIAPI_OK, cookie, 0);
182}
183
184/*
185 * T316 timeout function
186 */
187static void
188t316_func(struct uni *uni)
189{
190	uni_enq_start(uni, SIGS_T316, 0, NULL, NULL);
191}
192
193/*
194 * Q.2931:Reset-Start 1/2
195 */
196static void
197start_t316(struct uni *uni)
198{
199	if (uni->glob_start != UNI_CALLSTATE_REST1) {
200		VERBOSE0(uni, UNI_FAC_ERR, "T316 in state %d",
201		    uni->glob_start);
202		return;
203	}
204
205	if (++uni->cnt316 == uni->init316) {
206		struct uni_msg *app;
207		struct uniapi_reset_error_indication *resp;
208
209		VERBOSE(uni, UNI_FAC_RESTART, 1, "Reset-Start error");
210
211		resp = ALLOC_API(struct uniapi_reset_error_indication, app);
212		if (resp != NULL) {
213			resp->source = 0;
214			resp->reason = UNIAPI_RESET_ERROR_NO_RESPONSE,
215
216			uni->funcs->uni_output(uni, uni->arg,
217			    UNIAPI_RESET_ERROR_indication, 0, app);
218		}
219
220		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			(void)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				(void)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