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