Merge from vendor branch LESS:
[dragonfly.git] / sys / netproto / atm / uni / unisig_sigmgr_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_sigmgr_state.c,v 1.6 2000/01/17 20:49:58 mks Exp $
27  *      @(#) $DragonFly: src/sys/netproto/atm/uni/unisig_sigmgr_state.c,v 1.7 2006/01/14 13:36:39 swildner Exp $
28  */
29
30 /*
31  * ATM Forum UNI 3.0/3.1 Signalling Manager
32  * ----------------------------------------
33  *
34  * Signalling manager finite state machine
35  *
36  */
37
38 #include <netproto/atm/kern_include.h>
39
40 #include "uni.h"
41 #include "unisig.h"
42 #include "unisig_var.h"
43
44 /*
45  * Local functions
46  */
47 static int      unisig_sigmgr_invalid (struct unisig *, KBuffer *);
48 static int      unisig_sigmgr_act01 (struct unisig *, KBuffer *);
49 static int      unisig_sigmgr_act02 (struct unisig *, KBuffer *);
50 static int      unisig_sigmgr_act03 (struct unisig *, KBuffer *);
51 static int      unisig_sigmgr_act04 (struct unisig *, KBuffer *);
52 static int      unisig_sigmgr_act05 (struct unisig *, KBuffer *);
53 static int      unisig_sigmgr_act06 (struct unisig *, KBuffer *);
54 static int      unisig_sigmgr_act07 (struct unisig *, KBuffer *);
55 static int      unisig_sigmgr_act08 (struct unisig *, KBuffer *);
56 static int      unisig_sigmgr_act09 (struct unisig *, KBuffer *);
57 static int      unisig_sigmgr_act10 (struct unisig *, KBuffer *);
58 static int      unisig_sigmgr_act11 (struct unisig *, KBuffer *);
59 static int      unisig_sigmgr_act12 (struct unisig *, KBuffer *);
60 static int      unisig_sigmgr_act13 (struct unisig *, KBuffer *);
61 static int      unisig_sigmgr_act14 (struct unisig *, KBuffer *);
62
63
64 /*
65  * State table.
66  */
67 static int      sigmgr_state_table[10][7] = {
68     /*     0   1   2   3   4   5                                */
69         {  1,  0,  0,  0,  0 }, /* 0 - Time out         */
70         {  0,  0,  3,  5,  0 }, /* 1 - SSCF estab ind   */
71         {  0,  0,  3,  5,  0 }, /* 2 - SSCF estab cnf   */
72         {  0,  0,  4,  6,  0 }, /* 3 - SSCF release ind */
73         {  0,  0,  0,  6,  0 }, /* 4 - SSCF release cnf */
74         {  0,  0,  0,  7,  0 }, /* 5 - SSCF data ind    */
75         {  0,  0,  2,  2,  0 }, /* 6 - SSCF unit data ind */
76         {  0,  0,  8,  8,  8 }, /* 7 - Call cleared     */
77         { 14, 14, 14, 14,  0 }, /* 8 - Detach           */
78         { 13, 13,  0,  0,  0 }  /* 9 - Address set      */
79 };
80
81 /*
82  * Action vector
83  */
84 #define MAX_ACTION      15
85 static int (*unisig_sigmgr_act_vec[MAX_ACTION])
86                  (struct unisig *, KBuffer *) = {
87         unisig_sigmgr_invalid,
88         unisig_sigmgr_act01,
89         unisig_sigmgr_act02,
90         unisig_sigmgr_act03,
91         unisig_sigmgr_act04,
92         unisig_sigmgr_act05,
93         unisig_sigmgr_act06,
94         unisig_sigmgr_act07,
95         unisig_sigmgr_act08,
96         unisig_sigmgr_act09,
97         unisig_sigmgr_act10,
98         unisig_sigmgr_act11,
99         unisig_sigmgr_act12,
100         unisig_sigmgr_act13,
101         unisig_sigmgr_act14
102 };
103
104
105 /*
106  * ATM endpoint for UNI signalling channel
107  */
108 static Atm_endpoint     unisig_endpt = {
109         NULL,                   /* ep_next */
110         ENDPT_UNI_SIG,          /* ep_id */
111         NULL,                   /* ep_ioctl */
112         unisig_getname,         /* ep_getname */
113         unisig_connected,       /* ep_connected */
114         unisig_cleared,         /* ep_cleared */
115         NULL,                   /* ep_incoming */
116         NULL,                   /* ep_addparty */
117         NULL,                   /* ep_dropparty */
118         NULL,                   /* ep_cpcs_ctl */
119         NULL,                   /* ep_cpcs_data */
120         unisig_saal_ctl,        /* ep_saal_ctl */
121         unisig_saal_data,       /* ep_saal_data */
122         NULL,                   /* ep_sscop_ctl */
123         NULL                    /* ep_sscop_data */
124 };
125
126
127 /*
128  * ATM connection attributes for UNI signalling channel
129  */
130 static Atm_attributes   unisig_attr = {
131         NULL,                           /* nif */
132         CMAPI_SAAL,                     /* api */
133         UNI_VERS_3_0,                   /* api_init */
134         0,                              /* headin */
135         0,                              /* headout */
136         {                               /* aal */
137                 T_ATM_PRESENT,          /* aal.tag */
138                 ATM_AAL5                /* aal.aal_type */
139         },
140         {                               /* traffic */
141                 T_ATM_PRESENT,          /* traffic.tag */
142                 {                       /* traffic.v */
143                         {               /* traffic.v.forward */
144                                 T_ATM_ABSENT,   /* PCR_high */
145                                 0,              /* PCR_all */
146                                 T_ATM_ABSENT,   /* SCR_high */
147                                 T_ATM_ABSENT,   /* SCR_all */
148                                 T_ATM_ABSENT,   /* MBS_high */
149                                 T_ATM_ABSENT,   /* MBS_all */
150                                 T_NO,           /* tagging */
151                         },
152                         {               /* traffic.v.backward */
153                                 T_ATM_ABSENT,   /* PCR_high */
154                                 0,              /* PCR_all */
155                                 T_ATM_ABSENT,   /* SCR_high */
156                                 T_ATM_ABSENT,   /* SCR_all */
157                                 T_ATM_ABSENT,   /* MBS_high */
158                                 T_ATM_ABSENT,   /* MBS_all */
159                                 T_NO,           /* tagging */
160                         },
161                         T_YES,                  /* best_effort */
162                 }
163         },
164         {                               /* bearer */
165                 T_ATM_PRESENT,          /* bearer.tag */
166                 {                       /* bearer.v */
167                         T_ATM_CLASS_X,          /* class */
168                         T_ATM_NULL,             /* traffic_type */
169                         T_ATM_NO_END_TO_END,    /* timing_req */
170                         T_NO,                   /* clipping */
171                         T_ATM_1_TO_1,           /* conn_conf */
172                 }
173         },
174         {                               /* bhli */
175                 T_ATM_ABSENT,           /* bhli.tag */
176         },
177         {                               /* blli */
178                 T_ATM_ABSENT,           /* blli.tag_l2 */
179                 T_ATM_ABSENT,           /* blli.tag_l3 */
180         },
181         {                               /* llc */
182                 T_ATM_ABSENT,           /* llc.tag */
183         },
184         {                               /* called */
185                 T_ATM_PRESENT,          /* called.tag */
186         },
187         {                               /* calling */
188                 T_ATM_ABSENT,           /* calling.tag */
189         },
190         {                               /* qos */
191                 T_ATM_PRESENT,          /* qos.tag */
192                 {                       /* qos.v */
193                         T_ATM_NETWORK_CODING,   /* coding_standard */
194                         {                       /* qos.v.forward */
195                                 T_ATM_QOS_CLASS_0,      /* class */
196                         },
197                         {                       /* qos.v.backward */
198                                 T_ATM_QOS_CLASS_0,      /* class */
199                         }
200                 }
201         },
202         {                               /* transit */
203                 T_ATM_ABSENT,           /* transit.tag */
204         },
205         {                               /* cause */
206                 T_ATM_ABSENT,           /* cause.tag */
207         }
208 };
209
210
211 /*
212  * Finite state machine for the UNISIG signalling manager
213  *
214  * Arguments:
215  *      usp     pointer to the UNISIG protocol control block
216  *      event   indication of the event to be processed
217  *      m       pointer to a buffer with a message (optional)
218  *
219  * Returns:
220  *      0       success
221  *      errno   error encountered
222  *
223  */
224 int
225 unisig_sigmgr_state(struct unisig *usp, int event, KBuffer *m)
226 {
227         int             action, err = 0;
228
229         /*
230          * Cancel any signalling manager timer
231          */
232         UNISIG_CANCEL(usp);
233
234         /*
235          * Select an action based on the incoming event and
236          * the signalling manager's state
237          */
238         action = sigmgr_state_table[event][usp->us_state];
239         ATM_DEBUG4("unisig_sigmgr_state: usp=%p, state=%d, event=%d, action=%d\n",
240                         usp, usp->us_state, event, action);
241         if (action >= MAX_ACTION || action < 0) {
242                 panic("unisig_sigmgr_state: invalid action\n");
243         }
244
245         /*
246          * Perform the requested action
247          */
248         err = unisig_sigmgr_act_vec[action](usp, m);
249
250         return(err);
251 }
252
253
254 /*
255  * Signalling manager state machine action 0
256  *
257  * Invalid action
258  *
259  * Arguments:
260  *      usp     pointer to the UNISIG protocol control block
261  *      m       buffer pointer (may be NULL)
262  *
263  * Returns:
264  *      0       success
265  *      errno   error encountered
266  *
267  */
268 static int
269 unisig_sigmgr_invalid(struct unisig *usp, KBuffer *m)
270 {
271         log(LOG_ERR, "unisig_sigmgr_state: unexpected action\n");
272         if (m)
273                 KB_FREEALL(m);
274         return(0);
275 }
276
277
278 /*
279  * Signalling manager state machine action 1
280  *
281  * The kickoff timer has expired at attach time; go to
282  * UNISIG_ADDR_WAIT state.
283  *
284  * Arguments:
285  *      usp     pointer to the UNISIG protocol control block
286  *      m       buffer pointer (may be NULL)
287  *
288  * Returns:
289  *      0       success
290  *      errno   error encountered
291  *
292  */
293 static int
294 unisig_sigmgr_act01(struct unisig *usp, KBuffer *m)
295 {
296         /*
297          * Set the new state
298          */
299         usp->us_state = UNISIG_ADDR_WAIT;
300
301         return(0);
302 }
303
304
305 /*
306  * Signalling manager state machine action 2
307  *
308  * Ignore the event
309  *
310  * Arguments:
311  *      usp     pointer to the UNISIG protocol control block
312  *      m       buffer pointer (may be NULL)
313  *
314  * Returns:
315  *      0       success
316  *      errno   error encountered
317  *
318  */
319 static int
320 unisig_sigmgr_act02(struct unisig *usp, KBuffer *m)
321 {
322         /*
323          * Ignore event, discard message if present
324          */
325         if (m)
326                 KB_FREEALL(m);
327
328         return(0);
329 }
330
331
332 /*
333  * Signalling manager state machine action 3
334  *
335  * SSCF session on signalling channel has come up
336  *
337  * Arguments:
338  *      usp     pointer to the UNISIG protocol control block
339  *      m       buffer pointer (may be NULL)
340  *
341  * Returns:
342  *      0       success
343  *      errno   error encountered
344  *
345  */
346 static int
347 unisig_sigmgr_act03(struct unisig *usp, KBuffer *m)
348 {
349         struct unisig_vccb      *uvp, *vnext;
350
351         /*
352          * Log the activation
353          */
354         log(LOG_INFO, "unisig: signalling channel active\n");
355
356         /*
357          * Go to ACTIVE state
358          */
359         usp->us_state = UNISIG_ACTIVE;
360
361         /*
362          * Notify the VC state machine that the channel is up
363          */
364         for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb);
365                         uvp; uvp = vnext) {
366                 vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem);
367                 unisig_vc_state(usp, uvp, UNI_VC_SAAL_ESTAB,
368                                 (struct unisig_msg *) 0);
369         }
370
371         return(0);
372 }
373
374
375 /*
376  * Signalling manager state machine action 4
377  *
378  * A SSCF release indication was received.  Try to establish an
379  * SSCF session on the signalling PVC.
380  *
381  * Arguments:
382  *      usp     pointer to the UNISIG protocol control block
383  *      m       buffer pointer (may be NULL)
384  *
385  * Returns:
386  *      0       success
387  *      errno   error encountered
388  *
389  */
390 static int
391 unisig_sigmgr_act04(struct unisig *usp, KBuffer *m)
392 {
393         int             err;
394
395         /*
396          * Try to establish an SSCF session.
397          */
398         err = atm_cm_saal_ctl(SSCF_UNI_ESTABLISH_REQ,
399                         usp->us_conn,
400                         (void *)0);
401         if (err)
402                 panic("unisig_sigmgr_act04: SSCF_UNI_ESTABLISH_REQ");
403
404         return(0);
405 }
406
407
408 /*
409  * Signalling manager state machine action 5
410  *
411  * SSCF session on signalling channel has been reset
412  *
413  * Arguments:
414  *      usp     pointer to the UNISIG protocol control block
415  *      m       buffer pointer (may be NULL)
416  *
417  * Returns:
418  *      0       success
419  *      errno   error encountered
420  *
421  */
422 static int
423 unisig_sigmgr_act05(struct unisig *usp, KBuffer *m)
424 {
425         struct unisig_vccb      *uvp, *vnext;
426
427         /*
428          * Log the reset
429          */
430         log(LOG_INFO, "unisig: signalling channel reset\n");
431
432         /*
433          * Notify the VC state machine of the reset
434          */
435         for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb);
436                         uvp; uvp = vnext) {
437                 vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem);
438                 unisig_vc_state(usp, uvp, UNI_VC_SAAL_ESTAB,
439                                 (struct unisig_msg *) 0);
440         }
441
442         return(0);
443 }
444
445
446 /*
447  * Signalling manager state machine action 6
448  *
449  * SSCF session on signalling channel has been lost
450  *
451  * Arguments:
452  *      usp     pointer to the UNISIG protocol control block
453  *      m       buffer pointer (may be NULL)
454  *
455  * Returns:
456  *      0       success
457  *      errno   error encountered
458  *
459  */
460 static int
461 unisig_sigmgr_act06(struct unisig *usp, KBuffer *m)
462 {
463         struct unisig_vccb      *uvp, *vnext;
464
465         /*
466          * Log the fact that the session has been lost
467          */
468         log(LOG_INFO, "unisig: signalling channel SSCF session lost\n");
469
470         /*
471          * Notify the VC state machine of the loss
472          */
473         for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb);
474                         uvp; uvp = vnext) {
475                 vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem);
476                 unisig_vc_state(usp, uvp, UNI_VC_SAAL_FAIL,
477                                 (struct unisig_msg *) 0);
478         }
479
480         /*
481          * Try to restart the SSCF session
482          */
483         unisig_sigmgr_act04(usp, (KBuffer *) 0);
484
485         /*
486          * Go to INIT state
487          */
488         usp->us_state = UNISIG_INIT;
489
490         return(0);
491 }
492
493
494 /*
495  * Signalling manager state machine action 7
496  *
497  * A Q.2931 signalling message has been received
498  *
499  * Arguments:
500  *      usp     pointer to the UNISIG protocol control block
501  *      m       buffer pointer (may be NULL)
502  *
503  * Returns:
504  *      0       success
505  *      errno   error encountered
506  *
507  */
508 static int
509 unisig_sigmgr_act07(struct unisig *usp, KBuffer *m)
510 {
511         int     err;
512
513         /*
514          * Pass the Q.2931 signalling message on
515          * to the VC state machine
516          */
517         err = unisig_rcv_msg(usp, m);
518
519         return(err);
520 }
521
522
523 /*
524  * Signalling manager state machine action 8
525  *
526  * Process a CALL_CLOSED event for the signalling PVC
527  *
528  * Arguments:
529  *      usp     pointer to the UNISIG protocol control block
530  *      m       buffer pointer (may be NULL)
531  *
532  * Returns:
533  *      0       success
534  *      errno   error encountered
535  *
536  */
537 static int
538 unisig_sigmgr_act08(struct unisig *usp, KBuffer *m)
539 {
540
541         /*
542          * Signalling manager is now incommunicado
543          */
544         if (usp->us_state != UNISIG_DETACH) {
545                 /*
546                  * Log an error and set the state to NULL if
547                  * we're not detaching
548                  */
549                 log(LOG_ERR, "unisig: signalling channel closed\n");
550                 usp->us_state = UNISIG_NULL;
551         }
552         usp->us_conn = 0;
553
554         return(0);
555 }
556
557
558 /*
559  * Signalling manager state machine action 9
560  *
561  * Not used
562  *
563  * Arguments:
564  *      usp     pointer to the UNISIG protocol control block
565  *      m       buffer pointer (may be NULL)
566  *
567  * Returns:
568  *      0       success
569  *      errno   error encountered
570  *
571  */
572 static int
573 unisig_sigmgr_act09(struct unisig *usp, KBuffer *m)
574 {
575         log(LOG_ERR, "unisig_sigmgr_act09: unexpected action\n");
576         if (m)
577                 KB_FREEALL(m);
578         return (0);
579 }
580
581
582 /*
583  * Signalling manager state machine action 10
584  *
585  * Not used
586  *
587  * Arguments:
588  *      usp     pointer to the UNISIG protocol control block
589  *      m       buffer pointer (may be NULL)
590  *
591  * Returns:
592  *      0       success
593  *      errno   error encountered
594  *
595  */
596 static int
597 unisig_sigmgr_act10(struct unisig *usp, KBuffer *m)
598 {
599         return(0);
600 }
601
602
603 /*
604  * Signalling manager state machine action 11
605  *
606  * Not used
607  *
608  * Arguments:
609  *      usp     pointer to the UNISIG protocol control block
610  *      m       buffer pointer (may be NULL)
611  *
612  * Returns:
613  *      0       success
614  *      errno   error encountered
615  *
616  */
617 static int
618 unisig_sigmgr_act11(struct unisig *usp, KBuffer *m)
619 {
620         log(LOG_ERR, "unisig_sigmgr_act11: unexpected action\n");
621         if (m)
622                 KB_FREEALL(m);
623         return(0);
624 }
625
626
627 /*
628  * Signalling manager state machine action 12
629  *
630  * Not used
631  *
632  * Arguments:
633  *      usp     pointer to the UNISIG protocol control block
634  *      m       buffer pointer (may be NULL)
635  *
636  * Returns:
637  *      0       success
638  *      errno   error encountered
639  *
640  */
641 static int
642 unisig_sigmgr_act12(struct unisig *usp, KBuffer *m)
643 {
644         log(LOG_ERR, "unisig_sigmgr_act11: unexpected action\n");
645         if (m)
646                 KB_FREEALL(m);
647         return(0);
648 }
649
650
651 /*
652  * Signalling manager state machine action 13
653  *
654  * NSAP prefix has been set
655  *
656  * Arguments:
657  *      usp     pointer to the UNISIG protocol control block
658  *      m       buffer pointer (may be NULL)
659  *
660  * Returns:
661  *      0       success
662  *      errno   error encountered
663  *
664  */
665 static int
666 unisig_sigmgr_act13(struct unisig *usp, KBuffer *m)
667 {
668         int             err;
669         Atm_addr_pvc    *pvcp;
670
671         /*
672          * Set UNI signalling channel connection attributes
673          */
674         if (usp->us_proto == ATM_SIG_UNI30)
675                 unisig_attr.api_init = UNI_VERS_3_0;
676         else
677                 unisig_attr.api_init = UNI_VERS_3_1;
678
679         unisig_attr.nif = usp->us_pif->pif_nif;
680
681         unisig_attr.aal.v.aal5.forward_max_SDU_size = ATM_NIF_MTU;
682         unisig_attr.aal.v.aal5.backward_max_SDU_size = ATM_NIF_MTU;
683         unisig_attr.aal.v.aal5.SSCS_type = T_ATM_SSCS_SSCOP_REL;
684
685         unisig_attr.called.tag = T_ATM_PRESENT;
686         unisig_attr.called.addr.address_format = T_ATM_PVC_ADDR;
687         unisig_attr.called.addr.address_length = sizeof(Atm_addr_pvc);
688         pvcp = (Atm_addr_pvc *)unisig_attr.called.addr.address;
689         ATM_PVC_SET_VPI(pvcp, UNISIG_SIG_VPI);
690         ATM_PVC_SET_VCI(pvcp, UNISIG_SIG_VCI);
691         unisig_attr.called.subaddr.address_format = T_ATM_ABSENT;
692         unisig_attr.called.subaddr.address_length = 0;
693
694         unisig_attr.traffic.v.forward.PCR_all_traffic =
695                         usp->us_pif->pif_pcr;
696         unisig_attr.traffic.v.backward.PCR_all_traffic =
697                         usp->us_pif->pif_pcr;
698
699         /*
700          * Create UNISIG signalling channel
701          */
702         err = atm_cm_connect(&unisig_endpt, usp, &unisig_attr,
703                         &usp->us_conn);
704         if (err) {
705                 return(err);
706         }
707
708         /*
709          * Establish the SSCF session
710          */
711         err = atm_cm_saal_ctl(SSCF_UNI_ESTABLISH_REQ,
712                         usp->us_conn,
713                         (void *)0);
714         if (err)
715                 panic("unisig_sigmgr_act13: SSCF_UNI_ESTABLISH_REQ");
716
717         /*
718          * Set the new state
719          */
720         usp->us_state = UNISIG_INIT;
721
722         return(0);
723 }
724
725
726 /*
727  * Signalling manager state machine action 14
728  *
729  * Process a detach event
730  *
731  * Arguments:
732  *      usp     pointer to the UNISIG protocol control block
733  *      m       buffer pointer (may be NULL)
734  *
735  * Returns:
736  *      0       success
737  *      errno   error encountered
738  *
739  */
740 static int
741 unisig_sigmgr_act14(struct unisig *usp, KBuffer *m)
742 {
743         int                     err;
744         struct unisig_vccb      *sig_vccb, *uvp, *vnext;
745         struct atm_pif          *pip;
746         struct t_atm_cause      cause;
747
748         /*
749          * Locate the signalling channel's VCCB
750          */
751         sig_vccb = (struct unisig_vccb *)0;
752         if (usp->us_conn && usp->us_conn->co_connvc)
753                 sig_vccb = (struct unisig_vccb *)
754                                 usp->us_conn->co_connvc->cvc_vcc;
755
756         /*
757          * Terminate all of our VCCs
758          */
759         for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb);
760                         uvp; uvp = vnext) {
761                 vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem);
762
763                 /*
764                  * Don't close the signalling VCC yet
765                  */
766                 if (uvp == sig_vccb)
767                         continue;
768
769                 /*
770                  * Close VCC and notify owner
771                  */
772                 err = unisig_clear_vcc(usp, uvp,
773                                 T_ATM_CAUSE_NORMAL_CALL_CLEARING);
774         }
775
776         /*
777          * Close the signalling channel
778          */
779         if (usp->us_conn) {
780                 cause.coding_standard = T_ATM_ITU_CODING;
781                 cause.coding_standard = T_ATM_LOC_USER;
782                 cause.coding_standard = T_ATM_CAUSE_UNSPECIFIED_NORMAL;
783                 err = atm_cm_release(usp->us_conn, &cause);
784                 if (err)
785                         panic("unisig_sigmgr_act14: close failed\n");
786         }
787
788         /*
789          * Get rid of protocol instance if there are no VCCs queued
790          */
791         pip = usp->us_pif;
792         if (Q_HEAD(usp->us_vccq, struct vccb) == NULL &&
793                         pip->pif_sigmgr) {
794                 struct sigmgr   *smp = pip->pif_sigmgr;
795
796                 crit_enter();
797                 pip->pif_sigmgr = NULL;
798                 pip->pif_siginst = NULL;
799                 crit_exit();
800
801                 UNLINK((struct siginst *)usp, struct siginst,
802                                 smp->sm_prinst, si_next);
803                 KM_FREE(usp, sizeof(struct unisig), M_DEVBUF);
804         } else {
805                 /*
806                  * Otherwise, set new signalling manager state and
807                  * wait for protocol instance to be freed during 
808                  * unisig_free processing for the last queued VCC
809                  */
810                 usp->us_state = UNISIG_DETACH;
811         }
812
813         return (0);
814 }