Generally use NULL instead of explicitly casting 0 to some pointer type (part2).
[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                                 NULL);
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, usp->us_conn, NULL);
399         if (err)
400                 panic("unisig_sigmgr_act04: SSCF_UNI_ESTABLISH_REQ");
401
402         return(0);
403 }
404
405
406 /*
407  * Signalling manager state machine action 5
408  *
409  * SSCF session on signalling channel has been reset
410  *
411  * Arguments:
412  *      usp     pointer to the UNISIG protocol control block
413  *      m       buffer pointer (may be NULL)
414  *
415  * Returns:
416  *      0       success
417  *      errno   error encountered
418  *
419  */
420 static int
421 unisig_sigmgr_act05(struct unisig *usp, KBuffer *m)
422 {
423         struct unisig_vccb      *uvp, *vnext;
424
425         /*
426          * Log the reset
427          */
428         log(LOG_INFO, "unisig: signalling channel reset\n");
429
430         /*
431          * Notify the VC state machine of the reset
432          */
433         for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb);
434                         uvp; uvp = vnext) {
435                 vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem);
436                 unisig_vc_state(usp, uvp, UNI_VC_SAAL_ESTAB,
437                                 NULL);
438         }
439
440         return(0);
441 }
442
443
444 /*
445  * Signalling manager state machine action 6
446  *
447  * SSCF session on signalling channel has been lost
448  *
449  * Arguments:
450  *      usp     pointer to the UNISIG protocol control block
451  *      m       buffer pointer (may be NULL)
452  *
453  * Returns:
454  *      0       success
455  *      errno   error encountered
456  *
457  */
458 static int
459 unisig_sigmgr_act06(struct unisig *usp, KBuffer *m)
460 {
461         struct unisig_vccb      *uvp, *vnext;
462
463         /*
464          * Log the fact that the session has been lost
465          */
466         log(LOG_INFO, "unisig: signalling channel SSCF session lost\n");
467
468         /*
469          * Notify the VC state machine of the loss
470          */
471         for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb);
472                         uvp; uvp = vnext) {
473                 vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem);
474                 unisig_vc_state(usp, uvp, UNI_VC_SAAL_FAIL,
475                                 NULL);
476         }
477
478         /*
479          * Try to restart the SSCF session
480          */
481         unisig_sigmgr_act04(usp, NULL);
482
483         /*
484          * Go to INIT state
485          */
486         usp->us_state = UNISIG_INIT;
487
488         return(0);
489 }
490
491
492 /*
493  * Signalling manager state machine action 7
494  *
495  * A Q.2931 signalling message has been received
496  *
497  * Arguments:
498  *      usp     pointer to the UNISIG protocol control block
499  *      m       buffer pointer (may be NULL)
500  *
501  * Returns:
502  *      0       success
503  *      errno   error encountered
504  *
505  */
506 static int
507 unisig_sigmgr_act07(struct unisig *usp, KBuffer *m)
508 {
509         int     err;
510
511         /*
512          * Pass the Q.2931 signalling message on
513          * to the VC state machine
514          */
515         err = unisig_rcv_msg(usp, m);
516
517         return(err);
518 }
519
520
521 /*
522  * Signalling manager state machine action 8
523  *
524  * Process a CALL_CLOSED event for the signalling PVC
525  *
526  * Arguments:
527  *      usp     pointer to the UNISIG protocol control block
528  *      m       buffer pointer (may be NULL)
529  *
530  * Returns:
531  *      0       success
532  *      errno   error encountered
533  *
534  */
535 static int
536 unisig_sigmgr_act08(struct unisig *usp, KBuffer *m)
537 {
538
539         /*
540          * Signalling manager is now incommunicado
541          */
542         if (usp->us_state != UNISIG_DETACH) {
543                 /*
544                  * Log an error and set the state to NULL if
545                  * we're not detaching
546                  */
547                 log(LOG_ERR, "unisig: signalling channel closed\n");
548                 usp->us_state = UNISIG_NULL;
549         }
550         usp->us_conn = 0;
551
552         return(0);
553 }
554
555
556 /*
557  * Signalling manager state machine action 9
558  *
559  * Not used
560  *
561  * Arguments:
562  *      usp     pointer to the UNISIG protocol control block
563  *      m       buffer pointer (may be NULL)
564  *
565  * Returns:
566  *      0       success
567  *      errno   error encountered
568  *
569  */
570 static int
571 unisig_sigmgr_act09(struct unisig *usp, KBuffer *m)
572 {
573         log(LOG_ERR, "unisig_sigmgr_act09: unexpected action\n");
574         if (m)
575                 KB_FREEALL(m);
576         return (0);
577 }
578
579
580 /*
581  * Signalling manager state machine action 10
582  *
583  * Not used
584  *
585  * Arguments:
586  *      usp     pointer to the UNISIG protocol control block
587  *      m       buffer pointer (may be NULL)
588  *
589  * Returns:
590  *      0       success
591  *      errno   error encountered
592  *
593  */
594 static int
595 unisig_sigmgr_act10(struct unisig *usp, KBuffer *m)
596 {
597         return(0);
598 }
599
600
601 /*
602  * Signalling manager state machine action 11
603  *
604  * Not used
605  *
606  * Arguments:
607  *      usp     pointer to the UNISIG protocol control block
608  *      m       buffer pointer (may be NULL)
609  *
610  * Returns:
611  *      0       success
612  *      errno   error encountered
613  *
614  */
615 static int
616 unisig_sigmgr_act11(struct unisig *usp, KBuffer *m)
617 {
618         log(LOG_ERR, "unisig_sigmgr_act11: unexpected action\n");
619         if (m)
620                 KB_FREEALL(m);
621         return(0);
622 }
623
624
625 /*
626  * Signalling manager state machine action 12
627  *
628  * Not used
629  *
630  * Arguments:
631  *      usp     pointer to the UNISIG protocol control block
632  *      m       buffer pointer (may be NULL)
633  *
634  * Returns:
635  *      0       success
636  *      errno   error encountered
637  *
638  */
639 static int
640 unisig_sigmgr_act12(struct unisig *usp, KBuffer *m)
641 {
642         log(LOG_ERR, "unisig_sigmgr_act11: unexpected action\n");
643         if (m)
644                 KB_FREEALL(m);
645         return(0);
646 }
647
648
649 /*
650  * Signalling manager state machine action 13
651  *
652  * NSAP prefix has been set
653  *
654  * Arguments:
655  *      usp     pointer to the UNISIG protocol control block
656  *      m       buffer pointer (may be NULL)
657  *
658  * Returns:
659  *      0       success
660  *      errno   error encountered
661  *
662  */
663 static int
664 unisig_sigmgr_act13(struct unisig *usp, KBuffer *m)
665 {
666         int             err;
667         Atm_addr_pvc    *pvcp;
668
669         /*
670          * Set UNI signalling channel connection attributes
671          */
672         if (usp->us_proto == ATM_SIG_UNI30)
673                 unisig_attr.api_init = UNI_VERS_3_0;
674         else
675                 unisig_attr.api_init = UNI_VERS_3_1;
676
677         unisig_attr.nif = usp->us_pif->pif_nif;
678
679         unisig_attr.aal.v.aal5.forward_max_SDU_size = ATM_NIF_MTU;
680         unisig_attr.aal.v.aal5.backward_max_SDU_size = ATM_NIF_MTU;
681         unisig_attr.aal.v.aal5.SSCS_type = T_ATM_SSCS_SSCOP_REL;
682
683         unisig_attr.called.tag = T_ATM_PRESENT;
684         unisig_attr.called.addr.address_format = T_ATM_PVC_ADDR;
685         unisig_attr.called.addr.address_length = sizeof(Atm_addr_pvc);
686         pvcp = (Atm_addr_pvc *)unisig_attr.called.addr.address;
687         ATM_PVC_SET_VPI(pvcp, UNISIG_SIG_VPI);
688         ATM_PVC_SET_VCI(pvcp, UNISIG_SIG_VCI);
689         unisig_attr.called.subaddr.address_format = T_ATM_ABSENT;
690         unisig_attr.called.subaddr.address_length = 0;
691
692         unisig_attr.traffic.v.forward.PCR_all_traffic =
693                         usp->us_pif->pif_pcr;
694         unisig_attr.traffic.v.backward.PCR_all_traffic =
695                         usp->us_pif->pif_pcr;
696
697         /*
698          * Create UNISIG signalling channel
699          */
700         err = atm_cm_connect(&unisig_endpt, usp, &unisig_attr,
701                         &usp->us_conn);
702         if (err) {
703                 return(err);
704         }
705
706         /*
707          * Establish the SSCF session
708          */
709         err = atm_cm_saal_ctl(SSCF_UNI_ESTABLISH_REQ, usp->us_conn, NULL);
710         if (err)
711                 panic("unisig_sigmgr_act13: SSCF_UNI_ESTABLISH_REQ");
712
713         /*
714          * Set the new state
715          */
716         usp->us_state = UNISIG_INIT;
717
718         return(0);
719 }
720
721
722 /*
723  * Signalling manager state machine action 14
724  *
725  * Process a detach event
726  *
727  * Arguments:
728  *      usp     pointer to the UNISIG protocol control block
729  *      m       buffer pointer (may be NULL)
730  *
731  * Returns:
732  *      0       success
733  *      errno   error encountered
734  *
735  */
736 static int
737 unisig_sigmgr_act14(struct unisig *usp, KBuffer *m)
738 {
739         int                     err;
740         struct unisig_vccb      *sig_vccb, *uvp, *vnext;
741         struct atm_pif          *pip;
742         struct t_atm_cause      cause;
743
744         /*
745          * Locate the signalling channel's VCCB
746          */
747         sig_vccb = NULL;
748         if (usp->us_conn && usp->us_conn->co_connvc)
749                 sig_vccb = (struct unisig_vccb *)
750                                 usp->us_conn->co_connvc->cvc_vcc;
751
752         /*
753          * Terminate all of our VCCs
754          */
755         for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb);
756                         uvp; uvp = vnext) {
757                 vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem);
758
759                 /*
760                  * Don't close the signalling VCC yet
761                  */
762                 if (uvp == sig_vccb)
763                         continue;
764
765                 /*
766                  * Close VCC and notify owner
767                  */
768                 err = unisig_clear_vcc(usp, uvp,
769                                 T_ATM_CAUSE_NORMAL_CALL_CLEARING);
770         }
771
772         /*
773          * Close the signalling channel
774          */
775         if (usp->us_conn) {
776                 cause.coding_standard = T_ATM_ITU_CODING;
777                 cause.coding_standard = T_ATM_LOC_USER;
778                 cause.coding_standard = T_ATM_CAUSE_UNSPECIFIED_NORMAL;
779                 err = atm_cm_release(usp->us_conn, &cause);
780                 if (err)
781                         panic("unisig_sigmgr_act14: close failed\n");
782         }
783
784         /*
785          * Get rid of protocol instance if there are no VCCs queued
786          */
787         pip = usp->us_pif;
788         if (Q_HEAD(usp->us_vccq, struct vccb) == NULL &&
789                         pip->pif_sigmgr) {
790                 struct sigmgr   *smp = pip->pif_sigmgr;
791
792                 crit_enter();
793                 pip->pif_sigmgr = NULL;
794                 pip->pif_siginst = NULL;
795                 crit_exit();
796
797                 UNLINK((struct siginst *)usp, struct siginst,
798                                 smp->sm_prinst, si_next);
799                 KM_FREE(usp, sizeof(struct unisig), M_DEVBUF);
800         } else {
801                 /*
802                  * Otherwise, set new signalling manager state and
803                  * wait for protocol instance to be freed during 
804                  * unisig_free processing for the last queued VCC
805                  */
806                 usp->us_state = UNISIG_DETACH;
807         }
808
809         return (0);
810 }