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 
43 static void response_restart(struct uni *, struct uni_msg *, struct uni_all *);
44 static void response_status(struct uni *, struct uni_msg *, struct uni_all *);
45 
46 static void response_t317(struct uni *);
47 
48 static void response_error(struct uni *, struct uniapi_reset_error_response *,
49     uint32_t cookie);
50 static void response_response(struct uni *, struct uniapi_reset_response *,
51     uint32_t);
52 
53 static void start_request(struct uni *, struct uniapi_reset_request *,
54     uint32_t);
55 
56 static void start_t316(struct uni *);
57 
58 static void start_restart_ack(struct uni *, struct uni_msg *, struct uni_all *);
59 static void start_status(struct uni *, struct uni_msg *, struct uni_all *);
60 
61 static int restart_forward(struct uni *, const struct uni_all *);
62 
63 #define DEF_PRIV_SIG(NAME, FROM)	[SIG##NAME] =	"SIG"#NAME,
64 static 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,
70 static const char *const respond_sigs[] = {
71 	DEF_RESPOND_SIGS
72 };
73 #undef DEF_PRIV_SIG
74 
TIMER_FUNC_UNI(t317,t317_func)75 TIMER_FUNC_UNI(t317, t317_func)
76 TIMER_FUNC_UNI(t316, t316_func)
77 
78 /*
79  * Reset-Start process.
80  */
81 void
82 uni_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  */
142 static void
start_request(struct uni * uni,struct uniapi_reset_request * req,uint32_t cookie)143 start_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  */
187 static void
t316_func(struct uni * uni)188 t316_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  */
196 static void
start_t316(struct uni * uni)197 start_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  */
243 static void
start_restart_ack(struct uni * uni,struct uni_msg * m,struct uni_all * u)244 start_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  */
365 static void
start_status(struct uni * uni,struct uni_msg * m,struct uni_all * u)366 start_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  */
437 void
uni_sig_respond(struct uni * uni,u_int sig,uint32_t cookie,struct uni_msg * m,struct uni_all * u)438 uni_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  */
504 static int
restart_forward(struct uni * uni,const struct uni_all * u)505 restart_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  */
532 static void
response_restart(struct uni * uni,struct uni_msg * m,struct uni_all * u)533 response_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 
614 static void
response_t317(struct uni * uni)615 response_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  */
643 static void
response_error(struct uni * uni,struct uniapi_reset_error_response * c,uint32_t cookie)644 response_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  */
685 static void
response_response(struct uni * uni,struct uniapi_reset_response * arg,uint32_t cookie)686 response_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  */
747 static void
response_status(struct uni * uni,struct uni_msg * m,struct uni_all * u)748 response_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  */
823 static void
t317_func(struct uni * uni)824 t317_func(struct uni *uni)
825 {
826 	uni_enq_resp(uni, SIGR_T317, 0, NULL, NULL);
827 }
828