kernel tree reorganization stage 1: Major cvs repository work (not logged as
[dragonfly.git] / sys / netproto / atm / uni / unisig_vc_state.c
1 /*
2  *
3  * ===================================
4  * HARP  |  Host ATM Research Platform
5  * ===================================
6  *
7  *
8  * This Host ATM Research Platform ("HARP") file (the "Software") is
9  * made available by Network Computing Services, Inc. ("NetworkCS")
10  * "AS IS".  NetworkCS does not provide maintenance, improvements or
11  * support of any kind.
12  *
13  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17  * In no event shall NetworkCS be responsible for any damages, including
18  * but not limited to consequential damages, arising from or relating to
19  * any use of the Software or related support.
20  *
21  * Copyright 1994-1998 Network Computing Services, Inc.
22  *
23  * Copies of this Software may be made, however, the above copyright
24  * notice must be reproduced on all copies.
25  *
26  *      @(#) $FreeBSD: src/sys/netatm/uni/unisig_vc_state.c,v 1.6.2.1 2001/07/25 20:53:44 pirzyk Exp $
27  *      @(#) $DragonFly: src/sys/netproto/atm/uni/unisig_vc_state.c,v 1.3 2003/08/07 21:17:36 dillon Exp $
28  */
29
30 /*
31  * ATM Forum UNI 3.0/3.1 Signalling Manager
32  * ----------------------------------------
33  *
34  * VC state machine
35  *
36  */
37
38 #include <netatm/kern_include.h>
39
40 #include "unisig_var.h"
41 #include "unisig_msg.h"
42
43 /*
44  * Local functions
45  */
46 static int      unisig_vc_invalid __P((struct unisig *, struct unisig_vccb *,
47                         struct unisig_msg *));
48 static int      unisig_vc_act01 __P((struct unisig *, struct unisig_vccb *,
49                         struct unisig_msg *));
50 static int      unisig_vc_act02 __P((struct unisig *, struct unisig_vccb *,
51                         struct unisig_msg *));
52 static int      unisig_vc_act03 __P((struct unisig *, struct unisig_vccb *,
53                         struct unisig_msg *));
54 static int      unisig_vc_act04 __P((struct unisig *, struct unisig_vccb *,
55                         struct unisig_msg *));
56 static int      unisig_vc_act05 __P((struct unisig *, struct unisig_vccb *,
57                         struct unisig_msg *));
58 static int      unisig_vc_act06 __P((struct unisig *, struct unisig_vccb *,
59                         struct unisig_msg *));
60 static int      unisig_vc_act07 __P((struct unisig *, struct unisig_vccb *,
61                         struct unisig_msg *));
62 static int      unisig_vc_act08 __P((struct unisig *, struct unisig_vccb *,
63                         struct unisig_msg *));
64 static int      unisig_vc_act09 __P((struct unisig *, struct unisig_vccb *,
65                         struct unisig_msg *));
66 static int      unisig_vc_act10 __P((struct unisig *, struct unisig_vccb *,
67                         struct unisig_msg *));
68 static int      unisig_vc_act11 __P((struct unisig *, struct unisig_vccb *,
69                         struct unisig_msg *));
70 static int      unisig_vc_act12 __P((struct unisig *, struct unisig_vccb *,
71                         struct unisig_msg *));
72 static int      unisig_vc_act13 __P((struct unisig *, struct unisig_vccb *,
73                         struct unisig_msg *));
74 static int      unisig_vc_act14 __P((struct unisig *, struct unisig_vccb *,
75                         struct unisig_msg *));
76 static int      unisig_vc_act15 __P((struct unisig *, struct unisig_vccb *,
77                         struct unisig_msg *));
78 static int      unisig_vc_act16 __P((struct unisig *, struct unisig_vccb *,
79                         struct unisig_msg *));
80 static int      unisig_vc_act17 __P((struct unisig *, struct unisig_vccb *,
81                         struct unisig_msg *));
82 static int      unisig_vc_act18 __P((struct unisig *, struct unisig_vccb *,
83                         struct unisig_msg *));
84 static int      unisig_vc_act19 __P((struct unisig *, struct unisig_vccb *,
85                         struct unisig_msg *));
86 static int      unisig_vc_act20 __P((struct unisig *, struct unisig_vccb *,
87                         struct unisig_msg *));
88 static int      unisig_vc_act21 __P((struct unisig *, struct unisig_vccb *,
89                         struct unisig_msg *));
90 static int      unisig_vc_act22 __P((struct unisig *, struct unisig_vccb *,
91                         struct unisig_msg *));
92 static int      unisig_vc_act23 __P((struct unisig *, struct unisig_vccb *,
93                         struct unisig_msg *));
94 static int      unisig_vc_act24 __P((struct unisig *, struct unisig_vccb *,
95                         struct unisig_msg *));
96 static int      unisig_vc_act25 __P((struct unisig *, struct unisig_vccb *,
97                         struct unisig_msg *));
98 static int      unisig_vc_act26 __P((struct unisig *, struct unisig_vccb *,
99                         struct unisig_msg *));
100 static int      unisig_vc_act27 __P((struct unisig *, struct unisig_vccb *,
101                         struct unisig_msg *));
102 static int      unisig_vc_act28 __P((struct unisig *, struct unisig_vccb *,
103                         struct unisig_msg *));
104 static int      unisig_vc_act29 __P((struct unisig *, struct unisig_vccb *,
105                         struct unisig_msg *));
106 static int      unisig_vc_act30 __P((struct unisig *, struct unisig_vccb *,
107                         struct unisig_msg *));
108 static int      unisig_vc_act31 __P((struct unisig *, struct unisig_vccb *,
109                         struct unisig_msg *));
110 static int      unisig_vc_clear_call __P((struct unisig *,
111                         struct unisig_vccb *,
112                         struct unisig_msg *,
113                         int));
114
115
116 /*
117  * State table
118  */
119 static int      unisig_vc_states[21][17] = {
120 /* 0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16 */
121 {  0,  2, 99,  5, 99, 99,  0, 99, 12, 99,  0, 14,  0,  3,  0,  0,  0 },
122 { 29,  4, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17,  0,  0,  0,  0 },
123 { 29,  6, 99,  6, 99, 99, 17, 99, 17, 99, 17, 17, 17,  0,  0,  0,  0 },
124 { 29, 17, 99, 17, 99, 99, 17, 99, 10, 99, 17, 17, 17,  0,  0,  0,  0 },
125 {  8, 17, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17,  0,  0,  0,  0 },
126 { 29,  7, 99, 15, 99, 99, 15, 99, 15, 99, 15, 16, 17,  0,  0,  0,  0 },
127 { 19,  3, 99,  3, 99, 99,  3, 99,  3, 99,  3, 13,  3,  0,  0,  0,  0 },
128 { 21, 21, 99, 21, 99, 99, 21, 99, 21, 99, 21, 21, 21,  0,  0,  0,  0 },
129 { 22, 22, 99, 22, 99, 99, 22, 99, 22, 99, 22, 22, 22,  0,  0,  0,  0 },
130 { 29, 17, 99, 17, 99, 99, 17, 99, 17, 99, 23, 17, 17,  0,  0,  0,  0 },
131 { 29, 17, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17,  0,  0,  0,  0 },
132 { 29, 17, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17,  0,  0,  0,  0 },
133 { 29, 17, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17,  0,  0,  0,  0 },
134 { 29, 17, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17,  0,  0,  0,  0 },
135 {  1, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99 },
136 { 99, 25, 99, 25, 99, 99,  9, 99, 25, 99, 25, 25, 25, 25, 31, 25, 25 },
137 { 99, 25, 99, 25, 99, 99, 11, 99, 25, 99, 25, 25, 25, 25, 19, 25, 25 },
138 { 99, 12, 99, 12, 99, 99, 25, 99, 12, 99, 12, 19, 19, 30, 19, 99, 99 },
139 { 99, 12, 99, 12, 99, 99, 12, 99, 12, 99, 12,  3,  3,  3, 24, 26, 26 },
140 { 99,  3, 99,  3, 99, 99, 30, 99,  3, 99, 18,  3,  3,  0, 19, 27, 19 },
141 { 99,  7, 99,  7, 99, 99, 30, 99,  7, 99, 19, 19, 19, 20, 19, 19, 28 }
142 };
143
144
145 /*
146  * Action vector
147  *
148  * A given state, action pair selects an action number from the
149  * state table.  This vector holds the address of the action routine
150  * for each action number.
151  */
152 #define MAX_ACTION      32
153 static int (*unisig_vc_act_vec[MAX_ACTION])
154                 __P((struct unisig *, struct unisig_vccb *,
155                         struct unisig_msg *)) = {
156         unisig_vc_invalid,
157         unisig_vc_act01,        
158         unisig_vc_act02,
159         unisig_vc_act03,
160         unisig_vc_act04,
161         unisig_vc_act05,
162         unisig_vc_act06,
163         unisig_vc_act07,
164         unisig_vc_act08,
165         unisig_vc_act09,
166         unisig_vc_act10,
167         unisig_vc_act11,
168         unisig_vc_act12,
169         unisig_vc_act13,
170         unisig_vc_act14,
171         unisig_vc_act15,
172         unisig_vc_act16,
173         unisig_vc_act17,
174         unisig_vc_act18,
175         unisig_vc_act19,
176         unisig_vc_act20,
177         unisig_vc_act21,
178         unisig_vc_act22,
179         unisig_vc_act23,
180         unisig_vc_act24,
181         unisig_vc_act25,
182         unisig_vc_act26,
183         unisig_vc_act27,
184         unisig_vc_act28,
185         unisig_vc_act29,
186         unisig_vc_act30,
187         unisig_vc_act31
188 };
189
190
191 /*
192  * Process an event on a VC
193  *
194  * Arguments:
195  *      usp     pointer to the UNISIG instance
196  *      uvp     pointer to the VCCB for the affected VCC
197  *      event   a numeric indication of which event has occured
198  *      msg     pointer to a signalling message structure
199  *
200  * Returns:
201  *      0       success
202  *      errno   error encountered
203  *
204  */
205 int
206 unisig_vc_state(usp, uvp, event, msg)
207         struct unisig           *usp;
208         struct unisig_vccb      *uvp;
209         int                     event;
210         struct unisig_msg       *msg;
211 {
212         int     action, rc, state;
213
214         /*
215          * Select an action from the state table
216          */
217         if (uvp)
218                 state = uvp->uv_sstate;
219         else
220                 state = UNI_NULL;
221         action = unisig_vc_states[event][state];
222         if (action >= MAX_ACTION || action < 0)
223                 panic("unisig_vc_state: invalid action\n");
224
225         /*
226          * Perform the requested action
227          */
228         ATM_DEBUG4("unisig_vc_state: uvp=%p, state=%d, event=%d, action=%d\n",
229                         uvp, state, event, action);
230         rc = unisig_vc_act_vec[action](usp, uvp, msg);
231
232         return(rc);
233 }
234
235
236 /*
237  * VC state machine action 0
238  * Unexpected action - log an error message
239  *
240  * Arguments:
241  *      usp     pointer to protocol instance block
242  *      uvp     pointer to the VCCB for the affected connection (may
243                 be null)
244  *      msg     pointer to a UNISIG message structure
245  *
246  * Returns:
247  *      0       success
248  *      errno   error encountered
249  *
250  */
251 static int
252 unisig_vc_invalid(usp, uvp, msg)
253         struct unisig           *usp;
254         struct unisig_vccb      *uvp;
255         struct unisig_msg       *msg;
256 {
257         log(LOG_ERR, "unisig_vc_state: unexpected action\n");
258         return(EINVAL);
259 }
260
261
262 /*
263  * VC state machine action 1
264  * Setup handler called
265  *
266  * Send SETUP, start timer T303, go to UNI_CALL_INITIATED state
267  *
268  * Arguments:
269  *      usp     pointer to protocol instance block
270  *      uvp     pointer to the VCCB for the affected connection
271  *      msg     pointer to a UNISIG message structure
272  *
273  * Returns:
274  *      0       success
275  *      errno   error encountered
276  *
277  */
278 static int
279 unisig_vc_act01(usp, uvp, msg)
280         struct unisig           *usp;
281         struct unisig_vccb      *uvp;
282         struct unisig_msg       *msg;
283 {
284         int             rc;
285
286         /*
287          * Send the setup message
288          */
289         rc = unisig_send_setup(usp, uvp);
290         if (rc)
291                 return(rc);
292
293         /*
294          * Set timer T303
295          */
296         uvp->uv_retry = 0;
297         UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T303);
298
299         /*
300          * Set the new state
301          */
302         uvp->uv_sstate = UNI_CALL_INITIATED;
303
304         /*
305          * Mark the time
306          */
307         uvp->uv_tstamp = time_second;
308
309         return(0);
310 }
311
312
313 /*
314  * VC state machine action 2
315  * Timeout while waiting for CALL PROCEEDING or CONNECT
316  *
317  * If this is the second expiration, clear the call.  Otherwise,
318  * retransmit the SETUP message and restart T303.
319  *
320  * Arguments:
321  *      usp     pointer to protocol instance block
322  *      uvp     pointer to the VCCB for the affected connection
323  *      msg     pointer to a UNISIG message structure
324  *
325  * Returns:
326  *      0       success
327  *      errno   error encountered
328  *
329  */
330 static int
331 unisig_vc_act02(usp, uvp, msg)
332         struct unisig           *usp;
333         struct unisig_vccb      *uvp;
334         struct unisig_msg       *msg;
335 {
336         int     rc = 0;
337
338         if (uvp->uv_retry) {
339                 /*
340                  * Clear the call
341                  */
342                 rc = unisig_clear_vcc(usp, uvp,
343                                 T_ATM_CAUSE_NO_ROUTE_TO_DESTINATION);
344         } else {
345                 uvp->uv_retry++;
346                 (void) unisig_send_setup(usp, uvp);
347                 UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T303);
348         }
349         
350         return(rc);
351 }
352
353
354 /*
355  * VC state machine action 3
356  *
357  * Clear the call internally
358  *
359  * Arguments:
360  *      usp     pointer to protocol instance block
361  *      uvp     pointer to the VCCB for the affected connection
362  *      msg     pointer to a UNISIG message structure
363  *
364  * Returns:
365  *      0       success
366  *      errno   error encountered
367  *
368  */
369 static int
370 unisig_vc_act03(usp, uvp, msg)
371         struct unisig           *usp;
372         struct unisig_vccb      *uvp;
373         struct unisig_msg       *msg;
374 {
375         int     rc, cause;
376
377         /*
378          * Set cause code
379          */
380         if ((msg != NULL) && (msg->msg_ie_caus != NULL)) {
381                 unisig_cause_attr_from_ie(&uvp->uv_connvc->cvc_attr,
382                         msg->msg_ie_caus);
383                 cause = T_ATM_ABSENT;
384         } else
385                 cause = T_ATM_CAUSE_DESTINATION_OUT_OF_ORDER;
386
387         /*
388          * Clear the VCCB
389          */
390         rc = unisig_clear_vcc(usp, uvp, cause);
391
392         return(rc);
393 }
394
395
396 /*
397  * VC state machine action 4
398  * Received CALL PROCEEDING
399  *
400  * Start timer T310, go to UNI_CALL_OUT_PROC
401  *
402  * Arguments:
403  *      usp     pointer to protocol instance block
404  *      uvp     pointer to the VCCB for the affected connection
405  *      msg     pointer to a UNISIG message structure
406  *
407  * Returns:
408  *      0       success
409  *      errno   error encountered
410  *
411  */
412 static int
413 unisig_vc_act04(usp, uvp, msg)
414         struct unisig           *usp;
415         struct unisig_vccb      *uvp;
416         struct unisig_msg       *msg;
417 {
418         int                     cause, rc, vpi, vci;
419         struct atm_pif          *pip = usp->us_pif;
420         struct ie_generic       *iep;
421
422         /*
423          * Clear any running timer
424          */
425         UNISIG_VC_CANCEL((struct vccb *) uvp);
426
427         /*
428          * Make sure a Connection ID is part of the message
429          */
430         if (msg->msg_ie_cnid) {
431                 vpi = msg->msg_ie_cnid->ie_cnid_vpci;
432                 vci = msg->msg_ie_cnid->ie_cnid_vci;
433         } else {
434                 iep = (struct ie_generic *)atm_allocate(&unisig_iepool);
435                 if (!iep)
436                         return(ENOMEM);
437                 iep->ie_ident = UNI_IE_CNID;
438                 iep->ie_err_cause = UNI_IE_CAUS_MISSING;
439                 MSG_IE_ADD(msg, iep, UNI_MSG_IE_ERR);
440                 cause = UNI_IE_CAUS_MISSING;
441                 ATM_DEBUG0("unisig_vc_act04: no CNID in Call Proc\n");
442                 goto response04;
443         }
444
445         /*
446          * Make sure we can handle the specified VPI and VCI
447          */
448         if (vpi > pip->pif_maxvpi  || vci > pip->pif_maxvci ||
449                         vci < UNI_IE_CNID_MIN_VCI) {
450                 cause = UNI_IE_CAUS_BAD_VCC;
451                 ATM_DEBUG0("unisig_vc_act04: VPI/VCI invalid\n");
452                 goto response04;
453         }
454
455         /*
456          * Make sure the specified VPI and VCI are not in use
457          */
458         if (unisig_find_vpvc(usp, vpi, vci, VCC_OUT)) {
459                 cause = UNI_IE_CAUS_NA_VCC;
460                 ATM_DEBUG0("unisig_vc_act04: VPI/VCI in use\n");
461                 goto response04;
462         }
463
464         /*
465          * Start timer T310
466          */
467         UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T310);
468
469         /*
470          * Save the specified VPI and VCI
471          */
472         uvp->uv_vpi = vpi;
473         uvp->uv_vci = vci;
474
475         /*
476          * Set the state
477          */
478         uvp->uv_sstate = UNI_CALL_OUT_PROC;
479
480         /*
481          * Mark the time
482          */
483         uvp->uv_tstamp = time_second;
484
485         return(0);
486
487 response04:
488         /*
489          * Initiate call clearing
490          */
491         rc = unisig_vc_clear_call(usp, uvp, msg, cause);
492
493         return(rc);
494 }
495
496
497 /*
498  * VC state machine action 5
499  * Timeout in UNI_CALL_OUT_PROC
500  * 
501  * Clear call towards network
502  *
503  * Arguments:
504  *      usp     pointer to protocol instance block
505  *      uvp     pointer to the VCCB for the affected connection
506  *      msg     pointer to a UNISIG message structure
507  *
508  * Returns:
509  *      0       success
510  *      errno   error encountered
511  *
512  */
513 static int
514 unisig_vc_act05(usp, uvp, msg)
515         struct unisig           *usp;
516         struct unisig_vccb      *uvp;
517         struct unisig_msg       *msg;
518 {
519         int                     rc;
520         struct unisig_msg       *rls_msg;
521         struct ie_generic       *cause_ie;
522
523         /*
524          * Send a RELEASE message
525          */
526         rls_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
527         if (rls_msg == NULL)
528                 return(ENOMEM);
529         cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
530         if (cause_ie == NULL) {
531                 atm_free(rls_msg);
532                 return(ENOMEM);
533         }
534
535         /*
536          * Fill out the RELEASE message
537          */
538         rls_msg->msg_call_ref = uvp->uv_call_ref;
539         rls_msg->msg_type = UNI_MSG_RLSE;
540         rls_msg->msg_type_flag = 0;
541         rls_msg->msg_type_action = 0;
542         rls_msg->msg_ie_caus = cause_ie;
543
544         /*
545          * Fill out the cause IE
546          */
547         cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER;
548         cause_ie->ie_caus_cause = UNI_IE_CAUS_TIMER;
549         KM_COPY("310", cause_ie->ie_caus_diagnostic, 3);
550
551         /*
552          * Send the RELEASE message.
553          */
554         rc = unisig_send_msg(usp, rls_msg);
555         unisig_free_msg(rls_msg);
556
557         /*
558          * Start timer T308
559          */
560         UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T308);
561
562         /*
563          * Set the new state
564          */
565         uvp->uv_sstate = UNI_RELEASE_REQUEST;
566         uvp->uv_ustate = VCCU_CLOSED;
567
568         /*
569          * Mark the time
570          */
571         uvp->uv_tstamp = time_second;
572
573         return(rc);
574 }
575
576
577 /*
578  * VC state machine action 6
579  * Received CONNECT
580  *
581  * Send CONNECT ACK, go to UNI_ACTIVE state
582  *
583  * Arguments:
584  *      usp     pointer to protocol instance block
585  *      uvp     pointer to the VCCB for the affected connection
586  *      msg     pointer to a UNISIG message structure
587  *
588  * Returns:
589  *      0       success
590  *      errno   error encountered
591  *
592  */
593 static int
594 unisig_vc_act06(usp, uvp, msg)
595         struct unisig           *usp;
596         struct unisig_vccb      *uvp;
597         struct unisig_msg       *msg;
598 {
599         int                     cause, rc, vci, vpi;
600         struct atm_pif          *pip = usp->us_pif;
601         struct unisig_msg       *cack_msg;
602         struct ie_generic       *iep;
603         Atm_attributes          *ap;
604
605         /*
606          * Clear any running timer
607          */
608         UNISIG_VC_CANCEL((struct vccb *) uvp);
609
610         ap = &uvp->uv_connvc->cvc_attr;
611
612         /*
613          * See if a VPI/VCI is specified
614          */
615         if (msg->msg_ie_cnid) {
616                 /*
617                  * Yes--VPI/VCI must be the first specification or must
618                  * match what was specified before
619                  */
620                 vpi = msg->msg_ie_cnid->ie_cnid_vpci;
621                 vci = msg->msg_ie_cnid->ie_cnid_vci;
622                 if ((uvp->uv_vpi || uvp->uv_vci) &&
623                                 (vpi != uvp->uv_vpi ||
624                                 vci != uvp->uv_vci)) {
625                         cause = UNI_IE_CAUS_BAD_VCC;
626                         ATM_DEBUG0("unisig_vc_act06: VPI/VCI invalid\n");
627                         goto response06;
628                 }
629
630                 /*
631                  * Specified VPI/VCI must be within range
632                  */
633                 if (vpi > pip->pif_maxvpi || vci > pip->pif_maxvci ||
634                                 vci < UNI_IE_CNID_MIN_VCI) {
635                         cause = UNI_IE_CAUS_BAD_VCC;
636                         ATM_DEBUG0("unisig_vc_act06: VPI/VCI invalid\n");
637                         goto response06;
638                 }
639                 uvp->uv_vpi = vpi;
640                 uvp->uv_vci = vci;
641         } else {
642                 /*
643                  * No--VCI must have been specified earlier
644                  */
645                 if (!uvp->uv_vci) {
646                         iep = (struct ie_generic *)atm_allocate(
647                                         &unisig_iepool);
648                         if (!iep)
649                                 return(ENOMEM);
650                         iep->ie_ident = UNI_IE_CNID;
651                         iep->ie_err_cause = UNI_IE_CAUS_MISSING;
652                         MSG_IE_ADD(msg, iep, UNI_MSG_IE_ERR);
653                         cause = UNI_IE_CAUS_MISSING;
654                         ATM_DEBUG0("unisig_vc_act06: CNID missing\n");
655                         goto response06;
656                 }
657         }
658
659         /*
660          * Handle AAL parameters negotiation
661          */
662         if (msg->msg_ie_aalp) {
663                 struct ie_generic       *aalp = msg->msg_ie_aalp;
664
665                 /*
666                  * AAL parameters must have been sent in SETUP
667                  */
668                 if ((ap->aal.tag != T_ATM_PRESENT) ||
669                     (ap->aal.type != aalp->ie_aalp_aal_type)) {
670                         cause = UNI_IE_CAUS_IECONTENT;
671                         goto response06;
672                 }
673
674                 switch (aalp->ie_aalp_aal_type) {
675
676                 case UNI_IE_AALP_AT_AAL3:
677                         /*
678                          * Maximum SDU size negotiation
679                          */
680                         if (aalp->ie_aalp_4_fwd_max_sdu == T_ATM_ABSENT)
681                                 break;
682                         if ((ap->aal.v.aal4.forward_max_SDU_size < 
683                                         aalp->ie_aalp_4_fwd_max_sdu) ||
684                             (ap->aal.v.aal4.backward_max_SDU_size <
685                                         aalp->ie_aalp_4_bkwd_max_sdu)) {
686                                 cause = UNI_IE_CAUS_IECONTENT;
687                                 goto response06;
688                         } else {
689                                 ap->aal.v.aal4.forward_max_SDU_size =
690                                         aalp->ie_aalp_4_fwd_max_sdu;
691                                 ap->aal.v.aal4.backward_max_SDU_size =
692                                         aalp->ie_aalp_4_bkwd_max_sdu;
693                         }
694                         break;
695
696                 case UNI_IE_AALP_AT_AAL5:
697                         /*
698                          * Maximum SDU size negotiation
699                          */
700                         if (aalp->ie_aalp_5_fwd_max_sdu == T_ATM_ABSENT)
701                                 break;
702                         if ((ap->aal.v.aal5.forward_max_SDU_size < 
703                                         aalp->ie_aalp_5_fwd_max_sdu) ||
704                             (ap->aal.v.aal5.backward_max_SDU_size <
705                                         aalp->ie_aalp_5_bkwd_max_sdu)) {
706                                 cause = UNI_IE_CAUS_IECONTENT;
707                                 goto response06;
708                         } else {
709                                 ap->aal.v.aal5.forward_max_SDU_size =
710                                         aalp->ie_aalp_5_fwd_max_sdu;
711                                 ap->aal.v.aal5.backward_max_SDU_size =
712                                         aalp->ie_aalp_5_bkwd_max_sdu;
713                         }
714                         break;
715                 }
716         }
717
718         /*
719          * Get memory for a CONNECT ACK message
720          */
721         cack_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
722         if (cack_msg == NULL)
723                 return(ENOMEM);
724
725         /*
726          * Fill out the CONNECT ACK message
727          */
728         cack_msg->msg_call_ref = uvp->uv_call_ref;
729         cack_msg->msg_type = UNI_MSG_CACK;
730         cack_msg->msg_type_flag = 0;
731         cack_msg->msg_type_action = 0;
732
733         /*
734          * Send the CONNECT ACK message
735          */
736         rc = unisig_send_msg(usp, cack_msg);
737         unisig_free_msg(cack_msg);
738
739         /*
740          * Set the new state
741          */
742         uvp->uv_sstate = UNI_ACTIVE;
743         uvp->uv_ustate = VCCU_OPEN;
744
745         /*
746          * Mark the time
747          */
748         uvp->uv_tstamp = time_second;
749
750         /*
751          * Notify the user that the connection is now active
752          */
753         atm_cm_connected(uvp->uv_connvc);
754
755         return(0);
756
757 response06:
758         /*
759          * Initiate call clearing
760          */
761         rc = unisig_vc_clear_call(usp, uvp, msg, cause);
762
763         return(rc);
764 }
765
766
767 /*
768  * VC state machine action 7
769  * Abort routine called or signalling SAAL session reset while in
770  * one of the call setup states
771  *
772  * Clear the call, send RELEASE COMPLETE, notify the user.
773  *
774  * Arguments:
775  *      usp     pointer to protocol instance block
776  *      uvp     pointer to the VCCB for the affected connection
777  *      msg     pointer to a UNISIG message structure
778  *
779  * Returns:
780  *      0       success
781  *      errno   error encountered
782  *
783  */
784 static int
785 unisig_vc_act07(usp, uvp, msg)
786         struct unisig           *usp;
787         struct unisig_vccb      *uvp;
788         struct unisig_msg       *msg;
789 {
790         int                     rc;
791
792         /*
793          * Clear any running timer
794          */
795         UNISIG_VC_CANCEL((struct vccb *) uvp);
796
797         /*
798          * Send a RELEASE COMPLETE message rejecting the connection
799          */
800         rc = unisig_send_release_complete(usp, uvp, msg,
801                         UNI_IE_CAUS_TEMP);
802
803         /*
804          * Clear the call VCCB
805          */
806         uvp->uv_sstate = UNI_FREE;
807         uvp->uv_ustate = VCCU_CLOSED;
808
809         /*
810          * Mark the time
811          */
812         uvp->uv_tstamp = time_second;
813
814         /*
815          * Notify the user
816          */
817         if ((msg != NULL) && (msg->msg_ie_caus != NULL))
818                 unisig_cause_attr_from_ie(&uvp->uv_connvc->cvc_attr,
819                         msg->msg_ie_caus);
820         else
821                 unisig_cause_attr_from_user(&uvp->uv_connvc->cvc_attr,
822                         T_ATM_CAUSE_NORMAL_CALL_CLEARING);
823         atm_cm_cleared(uvp->uv_connvc);
824
825         return(rc);
826 }
827
828
829 /*
830  * VC state machine action 8
831  * Received SETUP
832  *
833  * Check call paramaters, notify user that a call has been received,
834  * set UNI_CALL_PRESENT state
835  *
836  * Arguments:
837  *      usp     pointer to protocol instance block
838  *      uvp     pointer to the VCCB for the affected connection
839  *      msg     pointer to a UNISIG message structure
840  *
841  * Returns:
842  *      0       success
843  *      errno   error encountered
844  *
845  */
846 static int
847 unisig_vc_act08(usp, uvp, msg)
848         struct unisig           *usp;
849         struct unisig_vccb      *uvp;
850         struct unisig_msg       *msg;
851 {
852         int                     cause = 0, rc, vpi, vci;
853         struct atm_pif          *pip = usp->us_pif;
854         struct atm_nif          *nip;
855         Atm_addr_nsap           *nap;
856         Atm_attributes          attr;
857
858         ATM_DEBUG3("unisig_vc_act08: usp=%p, uvp=%p, msg=%p\n",
859                         usp, uvp, msg);
860
861         /*
862          * Make sure that the called address is the right format
863          */
864         if (msg->msg_ie_cdad->ie_cdad_plan != UNI_IE_CDAD_PLAN_NSAP) {
865                 cause = UNI_IE_CAUS_IECONTENT;
866                 ATM_DEBUG0("unisig_vc_act08: bad address format\n");
867                 goto response08;
868         }
869
870         /*
871          * Make sure that the called address is ours
872          */
873         nap = (Atm_addr_nsap *) msg->msg_ie_cdad->ie_cdad_addr.address;
874         if (bcmp(usp->us_addr.address, nap,     /* XXX */
875                         sizeof(Atm_addr_nsap)-1)) {
876                 cause = UNI_IE_CAUS_IECONTENT;
877                 ATM_DEBUG0("unisig_vc_act08: address not mine\n");
878                 goto response08;
879         }
880
881         /*
882          * Find the right NIF for the given selector byte
883          */
884         nip = pip->pif_nif;
885         while (nip && nip->nif_sel != nap->aan_sel) {
886                 nip = nip->nif_pnext;
887         }
888         if (!nip) {
889                 cause = UNI_IE_CAUS_IECONTENT;
890                 ATM_DEBUG0("unisig_vc_act08: bad selector byte\n");
891                 goto response08;
892         }
893
894         /*
895          * See if we recognize the specified AAL
896          */
897         if (msg->msg_ie_aalp->ie_aalp_aal_type != UNI_IE_AALP_AT_AAL3 &&
898                         msg->msg_ie_aalp->ie_aalp_aal_type !=
899                         UNI_IE_AALP_AT_AAL5) {
900                 cause = UNI_IE_CAUS_UAAL;
901                 ATM_DEBUG0("unisig_vc_act08: bad AAL\n");
902                 goto response08;
903         }
904
905         /*
906          * Should verify that we can handle requested
907          * connection QOS
908          */
909
910         /*
911          * Make sure the specified VPI/VCI is valid
912          */
913         vpi = msg->msg_ie_cnid->ie_cnid_vpci;
914         vci = msg->msg_ie_cnid->ie_cnid_vci;
915         if (vpi > pip->pif_maxvpi ||
916                         vci > pip->pif_maxvci ||
917                         vci < UNI_IE_CNID_MIN_VCI) {
918                 cause = UNI_IE_CAUS_BAD_VCC;
919                 ATM_DEBUG0("unisig_vc_act08: VPI/VCI invalid\n");
920                 goto response08;
921         }
922
923         /*
924          * Make sure the specified VPI/VCI isn't in use already
925          */
926         if (unisig_find_vpvc(usp, vpi, vci, VCC_IN)) {
927                 cause = UNI_IE_CAUS_NA_VCC;
928                 ATM_DEBUG0("unisig_vc_act08: VPI/VCI in use\n");
929                 goto response08;
930         }
931
932         /*
933          * Make sure it's a point-to-point connection
934          */
935         if (msg->msg_ie_bbcp->ie_bbcp_conn_config !=
936                         UNI_IE_BBCP_CC_PP) {
937                 cause = UNI_IE_CAUS_NI_BC;
938                 ATM_DEBUG0("unisig_vc_act08: conn not pt-pt\n");
939                 goto response08;
940         }
941
942         /*
943          * Fill in the VCCB fields that we can at this point
944          */
945         uvp->uv_type = VCC_SVC | VCC_IN | VCC_OUT;
946         uvp->uv_proto = pip->pif_sigmgr->sm_proto;
947         uvp->uv_sstate = UNI_CALL_PRESENT;
948         uvp->uv_ustate = VCCU_POPEN;
949         uvp->uv_pif = pip;
950         uvp->uv_nif = nip;
951         uvp->uv_vpi = msg->msg_ie_cnid->ie_cnid_vpci;
952         uvp->uv_vci = msg->msg_ie_cnid->ie_cnid_vci;
953         uvp->uv_tstamp = time_second;
954
955         /*
956          * Copy the connection attributes from the SETUP message
957          * to an attribute block
958          */
959         KM_ZERO(&attr, sizeof(attr));
960         attr.nif = nip;
961         attr.aal.tag = T_ATM_ABSENT;
962         attr.traffic.tag = T_ATM_ABSENT;
963         attr.bearer.tag = T_ATM_ABSENT;
964         attr.bhli.tag = T_ATM_ABSENT;
965         attr.blli.tag_l2 = T_ATM_ABSENT;
966         attr.blli.tag_l3 = T_ATM_ABSENT;
967         attr.llc.tag = T_ATM_ABSENT;
968         attr.called.tag = T_ATM_ABSENT;
969         attr.calling.tag = T_ATM_ABSENT;
970         attr.qos.tag = T_ATM_ABSENT;
971         attr.transit.tag = T_ATM_ABSENT;
972         attr.cause.tag = T_ATM_ABSENT;
973         unisig_save_attrs(usp, msg, &attr);
974
975         /*
976          * Notify the connection manager of the new VCC
977          */
978         ATM_DEBUG0("unisig_vc_act08: notifying user of connection\n");
979         rc = atm_cm_incoming((struct vccb *)uvp, &attr);
980         if (rc)
981                 goto response08;
982
983         /*
984          * Wait for the connection recipient to issue an accept
985          * or reject
986          */
987         return(0);
988
989 response08:
990         ATM_DEBUG1("unisig_vc_act08: reject with cause=%d\n", cause);
991
992         /*
993          * Clear the VCCB state
994          */
995         uvp->uv_sstate = UNI_NULL;
996
997         /*
998          * Mark the time
999          */
1000         uvp->uv_tstamp = time_second;
1001
1002         /*
1003          * Some problem was detected with the request.  Send a Q.2931
1004          * message rejecting the connection.
1005          */
1006         rc = unisig_send_release_complete(usp, uvp, msg, cause);
1007
1008         return(rc);
1009 }
1010
1011
1012 /*
1013  * VC state machine action 9
1014  * Accept routine called by user
1015  *
1016  * Send CONNECT, start timer T313, go to UNI_CONNECT_REQUEST state
1017  *
1018  * Arguments:
1019  *      usp     pointer to protocol instance block
1020  *      uvp     pointer to the VCCB for the affected connection
1021  *      msg     pointer to a UNISIG message structure
1022  *
1023  * Returns:
1024  *      0       success
1025  *      errno   error encountered
1026  *
1027  */
1028 static int
1029 unisig_vc_act09(usp, uvp, msg)
1030         struct unisig           *usp;
1031         struct unisig_vccb      *uvp;
1032         struct unisig_msg       *msg;
1033 {
1034         int                     rc;
1035         struct unisig_msg       *conn_msg;
1036
1037         conn_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
1038         if (conn_msg == NULL)
1039                 return(ENOMEM);
1040
1041         /*
1042          * Fill out the response
1043          */
1044         conn_msg->msg_call_ref = uvp->uv_call_ref;
1045         conn_msg->msg_type = UNI_MSG_CONN;
1046         conn_msg->msg_type_flag = 0;
1047         conn_msg->msg_type_action = 0;
1048
1049         /*
1050          * Send the CONNECT message.  If the send fails, the other
1051          * side will eventually time out and close the connection.
1052          */
1053         rc = unisig_send_msg(usp, conn_msg);
1054         unisig_free_msg(conn_msg);
1055         if (rc) {
1056                 return(rc);
1057         }
1058
1059         /*
1060          * Start timer T313
1061          */
1062         UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T313);
1063
1064         /*
1065          * Set the new state
1066          */
1067         uvp->uv_sstate = UNI_CONNECT_REQUEST;
1068
1069         /*
1070          * Mark the time
1071          */
1072         uvp->uv_tstamp = time_second;
1073
1074         return(0);
1075 }
1076
1077
1078 /*
1079  * VC state machine action 10
1080  * Received CONNECT ACK
1081  *
1082  * Go to UNI_ACTIVE state
1083  *
1084  * Arguments:
1085  *      usp     pointer to protocol instance block
1086  *      uvp     pointer to the VCCB for the affected connection
1087  *      msg     pointer to a UNISIG message structure
1088  *
1089  * Returns:
1090  *      0       success
1091  *      errno   error encountered
1092  *
1093  */
1094 static int
1095 unisig_vc_act10(usp, uvp, msg)
1096         struct unisig           *usp;
1097         struct unisig_vccb      *uvp;
1098         struct unisig_msg       *msg;
1099 {
1100         /*
1101          * Clear any running timer
1102          */
1103         UNISIG_VC_CANCEL((struct vccb *) uvp);
1104
1105         /*
1106          * Set the state
1107          */
1108         uvp->uv_sstate = UNI_ACTIVE;
1109         uvp->uv_ustate = VCCU_OPEN;
1110
1111         /*
1112          * Mark the time
1113          */
1114         uvp->uv_tstamp = time_second;
1115
1116         /*
1117          * Notify the user that the call is up
1118          */
1119         atm_cm_connected(uvp->uv_connvc);
1120
1121         return (0);
1122 }
1123
1124
1125 /*
1126  * VC state machine action 11
1127  * Reject handler called
1128  *
1129  * Send RELEASE COMPLETE, clear the call
1130  *
1131  * Arguments:
1132  *      usp     pointer to protocol instance block
1133  *      uvp     pointer to the VCCB for the affected connection
1134  *      msg     pointer to a UNISIG message structure
1135  *
1136  * Returns:
1137  *      0       success
1138  *      errno   error encountered
1139  *
1140  */
1141 static int
1142 unisig_vc_act11(usp, uvp, msg)
1143         struct unisig           *usp;
1144         struct unisig_vccb      *uvp;
1145         struct unisig_msg       *msg;
1146 {
1147         int                     rc, cause;
1148
1149         /*
1150          * Send generic cause code if one is not already set
1151          */
1152         if (uvp->uv_connvc->cvc_attr.cause.tag == T_ATM_PRESENT)
1153                 cause = T_ATM_ABSENT;
1154         else
1155                 cause = T_ATM_CAUSE_CALL_REJECTED;
1156
1157         /*
1158          * Send a RELEASE COMPLETE message
1159          */
1160         rc = unisig_send_release_complete(usp, uvp, msg, cause);
1161
1162         /*
1163          * Clear the call VCCB
1164          */
1165         uvp->uv_sstate = UNI_FREE;
1166         uvp->uv_ustate = VCCU_CLOSED;
1167
1168         /*
1169          * Mark the time
1170          */
1171         uvp->uv_tstamp = time_second;
1172
1173         return(rc);
1174 }
1175
1176
1177 /*
1178  * VC state machine action 12
1179  * Release or abort routine called
1180  *
1181  * Send RELEASE, start timer T308, go to UNI_RELEASE_REQUEST state
1182  *
1183  * Arguments:
1184  *      usp     pointer to protocol instance block
1185  *      uvp     pointer to the VCCB for the affected connection
1186  *      msg     pointer to a UNISIG message structure
1187  *
1188  * Returns:
1189  *      0       success
1190  *      errno   error encountered
1191  *
1192  */
1193 static int
1194 unisig_vc_act12(usp, uvp, msg)
1195         struct unisig           *usp;
1196         struct unisig_vccb      *uvp;
1197         struct unisig_msg       *msg;
1198 {
1199         int                     rc;
1200
1201         /*
1202          * Clear any running timer
1203          */
1204         UNISIG_VC_CANCEL((struct vccb *) uvp);
1205
1206         /*
1207          * Send the RELEASE message
1208          */
1209         rc = unisig_vc_clear_call(usp, uvp, (struct unisig_msg *)NULL,
1210                         T_ATM_ABSENT);
1211
1212         return(rc);
1213 }
1214
1215
1216 /*
1217  * VC state machine action 13
1218  * RELEASE COMPLETE received
1219  *
1220  * Clear the call
1221  *
1222  * Arguments:
1223  *      usp     pointer to protocol instance block
1224  *      uvp     pointer to the VCCB for the affected connection
1225  *      msg     pointer to a UNISIG message structure
1226  *
1227  * Returns:
1228  *      0       success
1229  *      errno   error encountered
1230  *
1231  */
1232 static int
1233 unisig_vc_act13(usp, uvp, msg)
1234         struct unisig           *usp;
1235         struct unisig_vccb      *uvp;
1236         struct unisig_msg       *msg;
1237 {
1238         /*
1239          * Clear any running timer
1240          */
1241         UNISIG_VC_CANCEL((struct vccb *) uvp);
1242
1243         /*
1244          * Set the state
1245          */
1246         uvp->uv_sstate = UNI_FREE;
1247         if (uvp->uv_ustate != VCCU_ABORT)
1248                 uvp->uv_ustate = VCCU_CLOSED;
1249
1250         /*
1251          * Mark the time
1252          */
1253         uvp->uv_tstamp = time_second;
1254
1255         /*
1256          * Notify the user that the call is now closed
1257          */
1258         if (msg->msg_ie_caus != NULL)
1259                 unisig_cause_attr_from_ie(&uvp->uv_connvc->cvc_attr,
1260                         msg->msg_ie_caus);
1261         atm_cm_cleared(uvp->uv_connvc);
1262
1263         return(0);
1264 }
1265
1266
1267 /*
1268  * VC state machine action 14
1269  * Timer expired while waiting for RELEASE COMPLETE
1270  *
1271  * If this is the second expiration, just clear the call.  Otherwise,
1272  * retransmit the RELEASE message and restart timer T308.
1273  *
1274  * Arguments:
1275  *      usp     pointer to protocol instance block
1276  *      uvp     pointer to the VCCB for the affected connection
1277  *      msg     pointer to a UNISIG message structure
1278  *
1279  * Returns:
1280  *      0       success
1281  *      errno   error encountered
1282  *
1283  */
1284 static int
1285 unisig_vc_act14(usp, uvp, msg)
1286         struct unisig           *usp;
1287         struct unisig_vccb      *uvp;
1288         struct unisig_msg       *msg;
1289 {
1290         int                     rc;
1291
1292         /*
1293          * Check the retry count
1294          */
1295         if (uvp->uv_retry) {
1296                 /*
1297                  * Clear the connection
1298                  */
1299                 rc = unisig_clear_vcc(usp, uvp,
1300                                 T_ATM_CAUSE_NORMAL_CALL_CLEARING);
1301         } else {
1302                 /*
1303                  * Increment the retry count
1304                  */
1305                 uvp->uv_retry++;
1306
1307                 /*
1308                  * Resend the RELEASE message
1309                  */
1310                 rc = unisig_send_release(usp, uvp,
1311                                 (struct unisig_msg *)0, T_ATM_ABSENT);
1312                 if (rc)
1313                         return(rc);
1314
1315                 /*
1316                  * Restart timer T308
1317                  */
1318                 UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T308);
1319         }
1320
1321         return(0);
1322 }
1323
1324
1325 /*
1326  * VC state machine action 15
1327  * RELEASE received in UNI_ACTIVE state
1328  *
1329  * Send RELEASE COMPLETE, go to UNI_FREE, notify the user
1330  *
1331  * Arguments:
1332  *      usp     pointer to protocol instance block
1333  *      uvp     pointer to the VCCB for the affected connection
1334  *      msg     pointer to a UNISIG message structure
1335  *
1336  * Returns:
1337  *      0       success
1338  *      errno   error encountered
1339  *
1340  */
1341 static int
1342 unisig_vc_act15(usp, uvp, msg)
1343         struct unisig           *usp;
1344         struct unisig_vccb      *uvp;
1345         struct unisig_msg       *msg;
1346 {
1347         int                     cause, rc;
1348         struct ie_generic       *iep;
1349
1350         /*
1351          * Clear any running timer
1352          */
1353         UNISIG_VC_CANCEL((struct vccb *) uvp);
1354
1355         /*
1356          * If there was no Cause IE, flag an error
1357          */
1358         if (!msg->msg_ie_caus) {
1359                 cause = UNI_IE_CAUS_MISSING;
1360                 for (iep=msg->msg_ie_err; iep; iep=iep->ie_next) {
1361                         if (iep->ie_ident == UNI_IE_CAUS &&
1362                                         iep->ie_err_cause ==
1363                                         UNI_IE_CAUS_IECONTENT) {
1364                                 cause = UNI_IE_CAUS_IECONTENT;
1365                         }
1366                 }
1367                 if (cause == UNI_IE_CAUS_MISSING) {
1368                         iep = (struct ie_generic *)atm_allocate(
1369                                         &unisig_iepool);
1370                         if (!iep)
1371                                 return(ENOMEM);
1372                         iep->ie_ident = UNI_IE_CNID;
1373                         iep->ie_err_cause = UNI_IE_CAUS_MISSING;
1374                         MSG_IE_ADD(msg, iep, UNI_MSG_IE_ERR);
1375                 }
1376         } else {
1377                 cause = UNI_IE_CAUS_NORM_UNSP;
1378         }
1379
1380         /*
1381          * Send a RELEASE COMPLETE message
1382          */
1383         rc = unisig_send_release_complete(usp, uvp, msg, cause);
1384
1385         /*
1386          * Set the state
1387          */
1388         uvp->uv_sstate = UNI_FREE;
1389         uvp->uv_ustate = VCCU_CLOSED;
1390
1391         /*
1392          * Mark the time
1393          */
1394         uvp->uv_tstamp = time_second;
1395
1396         /*
1397          * Notify the user that the call is cleared
1398          */
1399         if (msg->msg_ie_caus != NULL)
1400                 unisig_cause_attr_from_ie(&uvp->uv_connvc->cvc_attr,
1401                         msg->msg_ie_caus);
1402         else
1403                 unisig_cause_attr_from_user(&uvp->uv_connvc->cvc_attr,
1404                         T_ATM_CAUSE_UNSPECIFIED_NORMAL);
1405         atm_cm_cleared(uvp->uv_connvc);
1406
1407         return(rc);
1408 }
1409
1410
1411 /*
1412  * VC state machine action 16
1413  * RELEASE received in UNI_RELEASE_REQUEST state
1414  *
1415  * Clear the call
1416  *
1417  * Arguments:
1418  *      usp     pointer to protocol instance block
1419  *      uvp     pointer to the VCCB for the affected connection
1420  *      msg     pointer to a UNISIG message structure
1421  *
1422  * Returns:
1423  *      0       success
1424  *      errno   error encountered
1425  *
1426  */
1427 static int
1428 unisig_vc_act16(usp, uvp, msg)
1429         struct unisig           *usp;
1430         struct unisig_vccb      *uvp;
1431         struct unisig_msg       *msg;
1432 {
1433         int     rc;
1434
1435         /*
1436          * Clear any running timer
1437          */
1438         UNISIG_VC_CANCEL((struct vccb *) uvp);
1439
1440         /*
1441          * Clear the VCCB
1442          */
1443         rc = unisig_clear_vcc(usp, uvp, T_ATM_ABSENT);
1444
1445         return(rc);
1446 }
1447
1448
1449 /*
1450  * VC state machine action 17
1451  * Protocol error
1452  *
1453  * Send a STATUS message with cause 101, "message not compatible with
1454  * call state"
1455  *
1456  * Arguments:
1457  *      usp     pointer to protocol instance block
1458  *      uvp     pointer to the VCCB for the affected connection
1459  *      msg     pointer to a UNISIG message structure
1460  *
1461  * Returns:
1462  *      0       success
1463  *      errno   error encountered
1464  *
1465  */
1466 static int
1467 unisig_vc_act17(usp, uvp, msg)
1468         struct unisig           *usp;
1469         struct unisig_vccb      *uvp;
1470         struct unisig_msg       *msg;
1471 {
1472         int                     rc;
1473
1474         ATM_DEBUG3("unisig_vc_perror: usp=%p, uvp=%p, msg=%p\n",
1475                         usp, uvp, msg);
1476
1477         /*
1478          * Clear any running timer
1479          */
1480         UNISIG_VC_CANCEL((struct vccb *) uvp);
1481
1482         /*
1483          * Send a STATUS message
1484          */
1485         rc = unisig_send_status(usp, uvp, msg, UNI_IE_CAUS_STATE);
1486
1487         return(rc ? rc : EINVAL);
1488 }
1489
1490
1491 /*
1492  * VC state machine action 18
1493  * Signalling AAL connection has been lost
1494  *
1495  * Start timer T309.  If the timer expires before the SAAL connection
1496  * comes back, the VCC will be cleared.
1497  *
1498  * Arguments:
1499  *      usp     pointer to protocol instance block
1500  *      uvp     pointer to the VCCB for the affected connection
1501  *      msg     pointer to a UNISIG message structure
1502  *
1503  * Returns:
1504  *      0       success
1505  *      errno   error encountered
1506  *
1507  */
1508 static int
1509 unisig_vc_act18(usp, uvp, msg)
1510         struct unisig           *usp;
1511         struct unisig_vccb      *uvp;
1512         struct unisig_msg       *msg;
1513 {
1514         /*
1515          * Clear any running timer
1516          */
1517         UNISIG_VC_CANCEL((struct vccb *) uvp);
1518
1519         /*
1520          * Start timer T309
1521          */
1522         UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T309);
1523
1524         /*
1525          * Set new state
1526          */
1527         uvp->uv_sstate = UNI_SSCF_RECOV;
1528
1529         return(0);
1530 }
1531
1532
1533 /*
1534  * VC state machine action 19
1535  * Ignore the event
1536  *
1537  * Arguments:
1538  *      usp     pointer to protocol instance block
1539  *      uvp     pointer to the VCCB for the affected connection
1540  *      msg     pointer to a UNISIG message structure
1541  *
1542  * Returns:
1543  *      0       success
1544  *      errno   error encountered
1545  *
1546  */
1547 static int
1548 unisig_vc_act19(usp, uvp, msg)
1549         struct unisig           *usp;
1550         struct unisig_vccb      *uvp;
1551         struct unisig_msg       *msg;
1552 {
1553         return(0);
1554 }
1555
1556
1557 /*
1558  * VC state machine action 20
1559  * SSCF establish indication in UNI_SSCF_RECOV state -- signalling
1560  * AAL has come up after an outage
1561  *
1562  * Send STATUS ENQ to make sure we're in compatible state with other end
1563  *
1564  * Arguments:
1565  *      usp     pointer to protocol instance block
1566  *      uvp     pointer to the VCCB for the affected connection
1567  *      msg     pointer to a UNISIG message structure
1568  *
1569  * Returns:
1570  *      0       success
1571  *      errno   error encountered
1572  *
1573  */
1574 static int
1575 unisig_vc_act20(usp, uvp, msg)
1576         struct unisig           *usp;
1577         struct unisig_vccb      *uvp;
1578         struct unisig_msg       *msg;
1579 {
1580         int                     rc;
1581         struct unisig_msg       *stat_msg;
1582
1583         /*
1584          * Clear any running timer
1585          */
1586         UNISIG_VC_CANCEL((struct vccb *) uvp);
1587
1588         /*
1589          * Get memory for a STATUS ENQUIRY message
1590          */
1591         stat_msg = (struct unisig_msg *)atm_allocate(&unisig_msgpool);
1592         if (stat_msg == NULL)
1593                 return(ENOMEM);
1594
1595         /*
1596          * Fill out the message
1597          */
1598         stat_msg->msg_call_ref = uvp->uv_call_ref;
1599         stat_msg->msg_type = UNI_MSG_SENQ;
1600         stat_msg->msg_type_flag = 0;
1601         stat_msg->msg_type_action = 0;
1602
1603         /*
1604          * Send the STATUS ENQUIRY message
1605          */
1606         rc = unisig_send_msg(usp, stat_msg);
1607         unisig_free_msg(stat_msg);
1608
1609         /*
1610          * Return to active state
1611          */
1612         uvp->uv_sstate = UNI_ACTIVE;
1613
1614         return(rc);
1615 }
1616
1617
1618 /*
1619  * VC state machine action 21
1620  * STATUS received
1621  *
1622  * Arguments:
1623  *      usp     pointer to protocol instance block
1624  *      uvp     pointer to the VCCB for the affected connection (may
1625  *              be NULL)
1626  *      msg     pointer to a UNISIG message structure
1627  *
1628  * Returns:
1629  *      0       success
1630  *      errno   error encountered
1631  *
1632  */
1633 static int
1634 unisig_vc_act21(usp, uvp, msg)
1635         struct unisig           *usp;
1636         struct unisig_vccb      *uvp;
1637         struct unisig_msg       *msg;
1638 {
1639         int     cause, rc;
1640
1641         /*
1642          * Ignore a STATUS message with the global call reference
1643          */
1644         if (GLOBAL_CREF(msg->msg_call_ref)) {
1645                 return(0);
1646         }
1647
1648         /*
1649          * If the network thinks we're in NULL state, clear the VCC
1650          */
1651         if (msg->msg_ie_clst->ie_clst_state == UNI_NULL) {
1652                 if (uvp) {
1653                         (void)unisig_clear_vcc(usp, uvp,
1654                                         T_ATM_CAUSE_DESTINATION_OUT_OF_ORDER);
1655                 }
1656                 return(0);
1657         }
1658
1659         /*
1660          * If we are in NULL state, send a RELEASE COMPLETE
1661          */
1662         if (!uvp || (uvp->uv_sstate == UNI_FREE) ||
1663                         (uvp->uv_sstate == UNI_NULL)) {
1664                 rc = unisig_send_release_complete(usp,
1665                                 uvp, msg, UNI_IE_CAUS_STATE);
1666                 return(rc);
1667         }
1668
1669         /*
1670          * If the reported state doesn't match our state, close the VCC
1671          * unless we're in UNI_RELEASE_REQUEST or UNI_RELEASE_IND
1672          */
1673         if (msg->msg_ie_clst->ie_clst_state != uvp->uv_sstate) {
1674                 if (uvp->uv_sstate == UNI_RELEASE_REQUEST ||
1675                                 uvp->uv_sstate == UNI_RELEASE_IND) {
1676                         return(0);
1677                 }
1678                 rc = unisig_clear_vcc(usp, uvp,
1679                         T_ATM_CAUSE_MESSAGE_INCOMPATIBLE_WITH_CALL_STATE);
1680         }
1681
1682         /*
1683          * States match, check for an error on one of our messages
1684          */
1685         cause = msg->msg_ie_caus->ie_caus_cause;
1686         if (cause == UNI_IE_CAUS_MISSING ||
1687                         cause == UNI_IE_CAUS_MTEXIST ||
1688                         cause == UNI_IE_CAUS_IEEXIST ||
1689                         cause == UNI_IE_CAUS_IECONTENT ||
1690                         cause == UNI_IE_CAUS_STATE) {
1691                 ATM_DEBUG2("unisig_vc_act21: error %d on message 0x%x\n",
1692                                 cause,
1693                                 msg->msg_ie_caus->ie_caus_diagnostic[0]);
1694                 if (uvp) {
1695                         (void)unisig_clear_vcc(usp, uvp, cause);
1696                 }
1697         }
1698
1699         return(0);
1700 }
1701
1702
1703 /*
1704  * VC state machine action 22
1705  * Received STATUS ENQ
1706  *
1707  * Send STATUS with cause 30 "response to STATUS ENQUIRY" and
1708  * current state
1709  *
1710  * Arguments:
1711  *      usp     pointer to protocol instance block
1712  *      uvp     pointer to the VCCB for the affected connection (may
1713  *              be NULL)
1714  *      msg     pointer to a UNISIG message structure
1715  *
1716  * Returns:
1717  *      0       success
1718  *      errno   error encountered
1719  *
1720  */
1721 static int
1722 unisig_vc_act22(usp, uvp, msg)
1723         struct unisig           *usp;
1724         struct unisig_vccb      *uvp;
1725         struct unisig_msg       *msg;
1726 {
1727         int                     rc;
1728         struct unisig_msg       *status;
1729         struct ie_generic       *callst_ie, *cause_ie;
1730
1731         ATM_DEBUG3("unisig_vc_perror: usp=%p, uvp=%p, msg=%p\n",
1732                         usp, uvp, msg);
1733
1734         /*
1735          * Get memory for a STATUS message
1736          */
1737         status = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
1738         if (status == NULL)
1739                 return(ENOMEM);
1740         callst_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
1741         if (callst_ie == NULL) {
1742                 atm_free(status);
1743                 return(ENOMEM);
1744         }
1745         cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
1746         if (cause_ie == NULL) {
1747                 atm_free(status);
1748                 atm_free(callst_ie);
1749                 return(ENOMEM);
1750         }
1751
1752         /*
1753          * Fill out the response
1754          */
1755         if (uvp) {
1756                 status->msg_call_ref = uvp->uv_call_ref;
1757         } else if (msg) {
1758                 if (msg->msg_call_ref & UNI_MSG_CALL_REF_RMT)
1759                         status->msg_call_ref = msg->msg_call_ref &
1760                                         UNI_MSG_CALL_REF_MASK;
1761                 else
1762                         status->msg_call_ref = msg->msg_call_ref |
1763                                         UNI_MSG_CALL_REF_RMT;
1764         } else {
1765                 status->msg_call_ref = UNI_MSG_CALL_REF_GLOBAL;
1766         }
1767         status->msg_type = UNI_MSG_STAT;
1768         status->msg_type_flag = 0;
1769         status->msg_type_action = 0;
1770         status->msg_ie_clst = callst_ie;
1771         status->msg_ie_caus = cause_ie;
1772
1773         /*
1774          * Fill out the call state IE
1775          */
1776         callst_ie->ie_ident = UNI_IE_CLST;
1777         callst_ie->ie_coding = 0;
1778         callst_ie->ie_flag = 0;
1779         callst_ie->ie_action = 0;
1780         if (uvp) {
1781                 switch(uvp->uv_sstate) {
1782                 case UNI_FREE:
1783                         callst_ie->ie_clst_state = UNI_NULL;
1784                         break;
1785                 default:
1786                         callst_ie->ie_clst_state = uvp->uv_sstate;
1787                 }
1788         } else {
1789                 callst_ie->ie_clst_state = UNI_NULL;
1790         }
1791
1792         /*
1793          * Fill out the cause IE
1794          */
1795         cause_ie->ie_ident = UNI_IE_CAUS;
1796         cause_ie->ie_coding = 0;
1797         cause_ie->ie_flag = 0;
1798         cause_ie->ie_action = 0;
1799         cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER;
1800         cause_ie->ie_caus_cause = UNI_IE_CAUS_SENQ;
1801
1802         /*
1803          * Send the STATUS message
1804          */
1805         rc = unisig_send_msg(usp, status);
1806         unisig_free_msg(status);
1807         return(rc);
1808 }
1809
1810
1811 /*
1812  * VC state machine action 23
1813  * Received ADD PARTY
1814  *
1815  * We don't support multipoint connections, so send an ADD PARTY REJECT
1816  *
1817  * Arguments:
1818  *      usp     pointer to protocol instance block
1819  *      uvp     pointer to the VCCB for the affected connection
1820  *      msg     pointer to a UNISIG message structure
1821  *
1822  * Returns:
1823  *      0       success
1824  *      errno   error encountered
1825  *
1826  */
1827 static int
1828 unisig_vc_act23(usp, uvp, msg)
1829         struct unisig           *usp;
1830         struct unisig_vccb      *uvp;
1831         struct unisig_msg       *msg;
1832 {
1833         int                     rc;
1834         struct unisig_msg       *apr_msg;
1835
1836         /*
1837          * Get memory for the ADD PARTY REJECT message
1838          */
1839         apr_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
1840         if (apr_msg == NULL)
1841                 return(ENOMEM);
1842
1843         /*
1844          * Fill out the message
1845          */
1846         if (msg->msg_call_ref & UNI_MSG_CALL_REF_RMT)
1847                 apr_msg->msg_call_ref = msg->msg_call_ref &
1848                                 UNI_MSG_CALL_REF_MASK;
1849         else
1850                 apr_msg->msg_call_ref = msg->msg_call_ref |
1851                                 UNI_MSG_CALL_REF_RMT;
1852         apr_msg->msg_type = UNI_MSG_ADPR;
1853         apr_msg->msg_type_flag = 0;
1854         apr_msg->msg_type_action = 0;
1855
1856         /*
1857          * Use the endpoint reference IE from the received message
1858          */
1859         apr_msg->msg_ie_eprf = msg->msg_ie_eprf;
1860
1861         /*
1862          * Send the ADD PARTY REJECT message
1863          */
1864         rc = unisig_send_msg(usp, apr_msg);
1865         apr_msg->msg_ie_eprf = NULL;
1866         unisig_free_msg(apr_msg);
1867
1868         return(rc);
1869 }
1870
1871
1872 /*
1873  * VC state machine action 24
1874  * User error
1875  *
1876  * Return EALREADY
1877  *
1878  * Arguments:
1879  *      usp     pointer to protocol instance block
1880  *      uvp     pointer to the VCCB for the affected connection
1881  *      msg     pointer to a UNISIG message structure
1882  *
1883  * Returns:
1884  *      0       success
1885  *      errno   error encountered
1886  *
1887  */
1888 static int
1889 unisig_vc_act24(usp, uvp, msg)
1890         struct unisig           *usp;
1891         struct unisig_vccb      *uvp;
1892         struct unisig_msg       *msg;
1893 {
1894         return(EALREADY);
1895 }
1896
1897
1898 /*
1899  * VC state machine action 25
1900  * User error
1901  *
1902  * Return EINVAL
1903  *
1904  * Arguments:
1905  *      usp     pointer to protocol instance block
1906  *      uvp     pointer to the VCCB for the affected connection
1907  *      msg     pointer to a UNISIG message structure
1908  *
1909  * Returns:
1910  *      0       success
1911  *      errno   error encountered
1912  *
1913  */
1914 static int
1915 unisig_vc_act25(usp, uvp, msg)
1916         struct unisig           *usp;
1917         struct unisig_vccb      *uvp;
1918         struct unisig_msg       *msg;
1919 {
1920         return(EINVAL);
1921 }
1922
1923
1924 /*
1925  * VC state machine action 26
1926  * PVC abort
1927  *
1928  * The abort handler was called to abort a PVC.  Clear the VCCB and
1929  * notify the user.
1930  *
1931  * Arguments:
1932  *      usp     pointer to protocol instance block
1933  *      uvp     pointer to the VCCB for the affected connection
1934  *      msg     pointer to a UNISIG message structure
1935  *
1936  * Returns:
1937  *      0       success
1938  *      errno   error encountered
1939  *
1940  */
1941 static int
1942 unisig_vc_act26(usp, uvp, msg)
1943         struct unisig           *usp;
1944         struct unisig_vccb      *uvp;
1945         struct unisig_msg       *msg;
1946 {
1947         int     rc;
1948
1949         /*
1950          * Clear any running timer
1951          */
1952         UNISIG_VC_CANCEL((struct vccb *) uvp);
1953
1954         /*
1955          * Close the VCCB
1956          */
1957         rc = unisig_close_vcc(usp, uvp);
1958         if (rc)
1959                 return(rc);
1960
1961         /*
1962          * Notify the user
1963          */
1964         if (uvp->uv_connvc->cvc_attr.cause.tag != T_ATM_PRESENT)
1965                 unisig_cause_attr_from_user(&uvp->uv_connvc->cvc_attr,
1966                         T_ATM_CAUSE_NORMAL_CALL_CLEARING);
1967
1968         atm_cm_cleared(uvp->uv_connvc);
1969
1970         return(0);
1971 }
1972
1973
1974 /*
1975  * VC state machine action 27
1976  * Signalling AAL failure
1977  *
1978  * Change PVC state to UNI_PVC_ACT_DOWN.
1979  *
1980  * Arguments:
1981  *      usp     pointer to protocol instance block
1982  *      uvp     pointer to the VCCB for the affected connection
1983  *      msg     pointer to a UNISIG message structure
1984  *
1985  * Returns:
1986  *      0       success
1987  *      errno   error encountered
1988  *
1989  */
1990 static int
1991 unisig_vc_act27(usp, uvp, msg)
1992         struct unisig           *usp;
1993         struct unisig_vccb      *uvp;
1994         struct unisig_msg       *msg;
1995 {
1996         /*
1997          * Set the state
1998          */
1999         uvp->uv_sstate = UNI_PVC_ACT_DOWN;
2000
2001         /*
2002          * Mark the time
2003          */
2004         uvp->uv_tstamp = time_second;
2005
2006         return(0);
2007 }
2008
2009
2010 /*
2011  * VC state machine action 28
2012  * Signalling AAL established
2013  *
2014  * Set PVC state to UNI_PVC_ACTIVE.
2015  *
2016  * Arguments:
2017  *      usp     pointer to protocol instance block
2018  *      uvp     pointer to the VCCB for the affected connection
2019  *      msg     pointer to a UNISIG message structure
2020  *
2021  * Returns:
2022  *      0       success
2023  *      errno   error encountered
2024  *
2025  */
2026 static int
2027 unisig_vc_act28(usp, uvp, msg)
2028         struct unisig           *usp;
2029         struct unisig_vccb      *uvp;
2030         struct unisig_msg       *msg;
2031 {
2032         /*
2033          * Set the state
2034          */
2035         uvp->uv_sstate = UNI_PVC_ACTIVE;
2036
2037         /*
2038          * Mark the time
2039          */
2040         uvp->uv_tstamp = time_second;
2041
2042         return(0);
2043 }
2044
2045
2046 /*
2047  * VC state machine action 29
2048  * Protocol error
2049  *
2050  * Send a RELEASE COMPLETE message with cause 81, "invalid call
2051  * reference value"
2052  *
2053  * Arguments:
2054  *      usp     pointer to protocol instance block
2055  *      uvp     pointer to the VCCB for the affected connection (may
2056  *              be NULL)
2057  *      msg     pointer to a UNISIG message structure
2058  *
2059  * Returns:
2060  *      0       success
2061  *      errno   error encountered
2062  *
2063  */
2064 static int
2065 unisig_vc_act29(usp, uvp, msg)
2066         struct unisig           *usp;
2067         struct unisig_vccb      *uvp;
2068         struct unisig_msg       *msg;
2069 {
2070         int                     rc;
2071
2072         /*
2073          * Send a RELEASE COMPLETE message
2074          */
2075         rc = unisig_send_release_complete(usp, uvp, msg,
2076                         UNI_IE_CAUS_CREF);
2077
2078         return(rc);
2079 }
2080
2081
2082 /*
2083  * VC state machine action 30
2084  * Release routine called while SSCF session down, or SSCF session
2085  * reset or lost while in UNI_CALL_PRESENT
2086  *
2087  * Go to UNI_FREE state
2088  *
2089  * Arguments:
2090  *      usp     pointer to protocol instance block
2091  *      uvp     pointer to the VCCB for the affected connection
2092  *      msg     pointer to a UNISIG message structure
2093  *
2094  * Returns:
2095  *      0       success
2096  *      errno   error encountered
2097  *
2098  */
2099 static int
2100 unisig_vc_act30(usp, uvp, msg)
2101         struct unisig           *usp;
2102         struct unisig_vccb      *uvp;
2103         struct unisig_msg       *msg;
2104 {
2105         /*
2106          * Clear any running timer
2107          */
2108         UNISIG_VC_CANCEL((struct vccb *) uvp);
2109
2110         /*
2111          * Clear the call state
2112          */
2113         uvp->uv_sstate = UNI_FREE;
2114         uvp->uv_ustate = VCCU_CLOSED;
2115
2116         /*
2117          * Mark the time
2118          */
2119         uvp->uv_tstamp = time_second;
2120
2121         return(0);
2122 }
2123
2124
2125 /*
2126  * VC state machine action 31
2127  * Accept handler called in UNI_FREE state.
2128  *
2129  * The call was in UNI_CALL_PRESENT state when it was closed because
2130  * of an SSCF failure.  Return an error indication.  The accept
2131  * handler will free the VCCB and return the proper code to the
2132  * caller.
2133  *
2134  * Arguments:
2135  *      usp     pointer to protocol instance block
2136  *      uvp     pointer to the VCCB for the affected connection
2137  *      msg     pointer to a UNISIG message structure
2138  *
2139  * Returns:
2140  *      0       success
2141  *      errno   error encountered
2142  *
2143  */
2144 static int
2145 unisig_vc_act31(usp, uvp, msg)
2146         struct unisig           *usp;
2147         struct unisig_vccb      *uvp;
2148         struct unisig_msg       *msg;
2149 {
2150         return(ENETDOWN);
2151 }
2152
2153
2154 /*
2155  * Initiate clearing a call by sending a RELEASE message.
2156  *
2157  * Arguments:
2158  *      usp     pointer to protocol instance block
2159  *      uvp     pointer to the VCCB for the affected connection
2160  *      msg     pointer to UNI signalling message that the RELEASE
2161  *              responds to (may be NULL)
2162  *      cause   the reason for clearing the call;  a value of
2163  *              T_ATM_ABSENT indicates that the cause code is
2164  *              in the VCC's ATM attributes block
2165  *
2166  * Returns:
2167  *      0       success
2168  *      errno   error encountered
2169  *
2170  */
2171 static int
2172 unisig_vc_clear_call(usp, uvp, msg, cause)
2173         struct unisig           *usp;
2174         struct unisig_vccb      *uvp;
2175         struct unisig_msg       *msg;
2176         int                     cause;
2177 {
2178         int                     rc;
2179
2180         /*
2181          * Clear the retry count
2182          */
2183         uvp->uv_retry = 0;
2184
2185         /*
2186          * Make sure the ATM attributes block has a valid cause code,
2187          * if needed
2188          */
2189         if (cause == T_ATM_ABSENT &&
2190                         uvp->uv_connvc->cvc_attr.cause.tag !=
2191                         T_ATM_PRESENT) {
2192                 uvp->uv_connvc->cvc_attr.cause.tag = T_ATM_PRESENT;
2193                 uvp->uv_connvc->cvc_attr.cause.v.coding_standard =
2194                                 T_ATM_ITU_CODING;
2195                 uvp->uv_connvc->cvc_attr.cause.v.location =
2196                                 T_ATM_LOC_USER;
2197                 uvp->uv_connvc->cvc_attr.cause.v.cause_value =
2198                         usp->us_proto == ATM_SIG_UNI30 ? 
2199                                 T_ATM_CAUSE_UNSPECIFIED_NORMAL :
2200                                 T_ATM_CAUSE_NORMAL_CALL_CLEARING;
2201         }
2202
2203         /*
2204          * Send a RELEASE message
2205          */
2206         rc = unisig_send_release(usp, uvp, msg, cause);
2207         if (rc)
2208                 return(rc);
2209
2210         /*
2211          * Start timer T308
2212          */
2213         UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T308);
2214
2215         /*
2216          * Set the VCCB state
2217          */
2218         uvp->uv_sstate = UNI_RELEASE_REQUEST;
2219         if (uvp->uv_ustate != VCCU_ABORT)
2220                 uvp->uv_ustate = VCCU_CLOSED;
2221
2222         /*
2223          * Mark the time
2224          */
2225         uvp->uv_tstamp = time_second;
2226
2227         return(0);
2228 }