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