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