]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/contrib/ngatm/netnatm/sig/sig_reset.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / contrib / ngatm / netnatm / sig / sig_reset.c
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 }