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
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
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
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
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
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
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
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
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
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
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
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
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
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
824 t317_func(struct uni *uni)
825 {
826 uni_enq_resp(uni, SIGR_T317, 0, NULL, NULL);
827 }
Cache object: 6e6bcb35bcfdc933be9560149f6a4d0f
|