Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[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.2 2003/06/17 04:28:49 dillon 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 <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 /*
45  * Local functions
46  */
47 static int      unisig_sigmgr_invalid __P((struct unisig *, KBuffer *));
48 static int      unisig_sigmgr_act01 __P((struct unisig *, KBuffer *));
49 static int      unisig_sigmgr_act02 __P((struct unisig *, KBuffer *));
50 static int      unisig_sigmgr_act03 __P((struct unisig *, KBuffer *));
51 static int      unisig_sigmgr_act04 __P((struct unisig *, KBuffer *));
52 static int      unisig_sigmgr_act05 __P((struct unisig *, KBuffer *));
53 static int      unisig_sigmgr_act06 __P((struct unisig *, KBuffer *));
54 static int      unisig_sigmgr_act07 __P((struct unisig *, KBuffer *));
55 static int      unisig_sigmgr_act08 __P((struct unisig *, KBuffer *));
56 static int      unisig_sigmgr_act09 __P((struct unisig *, KBuffer *));
57 static int      unisig_sigmgr_act10 __P((struct unisig *, KBuffer *));
58 static int      unisig_sigmgr_act11 __P((struct unisig *, KBuffer *));
59 static int      unisig_sigmgr_act12 __P((struct unisig *, KBuffer *));
60 static int      unisig_sigmgr_act13 __P((struct unisig *, KBuffer *));
61 static int      unisig_sigmgr_act14 __P((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                  __P((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(usp, event, m)
226         struct unisig   *usp;
227         int             event;
228         KBuffer         *m;
229 {
230         int             action, err = 0;
231
232         /*
233          * Cancel any signalling manager timer
234          */
235         UNISIG_CANCEL(usp);
236
237         /*
238          * Select an action based on the incoming event and
239          * the signalling manager's state
240          */
241         action = sigmgr_state_table[event][usp->us_state];
242         ATM_DEBUG4("unisig_sigmgr_state: usp=%p, state=%d, event=%d, action=%d\n",
243                         usp, usp->us_state, event, action);
244         if (action >= MAX_ACTION || action < 0) {
245                 panic("unisig_sigmgr_state: invalid action\n");
246         }
247
248         /*
249          * Perform the requested action
250          */
251         err = unisig_sigmgr_act_vec[action](usp, m);
252
253         return(err);
254 }
255
256
257 /*
258  * Signalling manager state machine action 0
259  *
260  * Invalid action
261  *
262  * Arguments:
263  *      usp     pointer to the UNISIG protocol control block
264  *      m       buffer pointer (may be NULL)
265  *
266  * Returns:
267  *      0       success
268  *      errno   error encountered
269  *
270  */
271 static int
272 unisig_sigmgr_invalid(usp, m)
273         struct unisig   *usp;
274         KBuffer         *m;
275 {
276         log(LOG_ERR, "unisig_sigmgr_state: unexpected action\n");
277         if (m)
278                 KB_FREEALL(m);
279         return(0);
280 }
281
282
283 /*
284  * Signalling manager state machine action 1
285  *
286  * The kickoff timer has expired at attach time; go to
287  * UNISIG_ADDR_WAIT state.
288  *
289  * Arguments:
290  *      usp     pointer to the UNISIG protocol control block
291  *      m       buffer pointer (may be NULL)
292  *
293  * Returns:
294  *      0       success
295  *      errno   error encountered
296  *
297  */
298 static int
299 unisig_sigmgr_act01(usp, m)
300         struct unisig   *usp;
301         KBuffer         *m;
302 {
303         /*
304          * Set the new state
305          */
306         usp->us_state = UNISIG_ADDR_WAIT;
307
308         return(0);
309 }
310
311
312 /*
313  * Signalling manager state machine action 2
314  *
315  * Ignore the event
316  *
317  * Arguments:
318  *      usp     pointer to the UNISIG protocol control block
319  *      m       buffer pointer (may be NULL)
320  *
321  * Returns:
322  *      0       success
323  *      errno   error encountered
324  *
325  */
326 static int
327 unisig_sigmgr_act02(usp, m)
328         struct unisig   *usp;
329         KBuffer         *m;
330 {
331         /*
332          * Ignore event, discard message if present
333          */
334         if (m)
335                 KB_FREEALL(m);
336
337         return(0);
338 }
339
340
341 /*
342  * Signalling manager state machine action 3
343  *
344  * SSCF session on signalling channel has come up
345  *
346  * Arguments:
347  *      usp     pointer to the UNISIG protocol control block
348  *      m       buffer pointer (may be NULL)
349  *
350  * Returns:
351  *      0       success
352  *      errno   error encountered
353  *
354  */
355 static int
356 unisig_sigmgr_act03(usp, m)
357         struct unisig   *usp;
358         KBuffer         *m;
359 {
360         struct unisig_vccb      *uvp, *vnext;
361
362         /*
363          * Log the activation
364          */
365         log(LOG_INFO, "unisig: signalling channel active\n");
366
367         /*
368          * Go to ACTIVE state
369          */
370         usp->us_state = UNISIG_ACTIVE;
371
372         /*
373          * Notify the VC state machine that the channel is up
374          */
375         for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb);
376                         uvp; uvp = vnext) {
377                 vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem);
378                 (void) unisig_vc_state(usp, uvp, UNI_VC_SAAL_ESTAB,
379                                 (struct unisig_msg *) 0);
380         }
381
382         return(0);
383 }
384
385
386 /*
387  * Signalling manager state machine action 4
388  *
389  * A SSCF release indication was received.  Try to establish an
390  * SSCF session on the signalling PVC.
391  *
392  * Arguments:
393  *      usp     pointer to the UNISIG protocol control block
394  *      m       buffer pointer (may be NULL)
395  *
396  * Returns:
397  *      0       success
398  *      errno   error encountered
399  *
400  */
401 static int
402 unisig_sigmgr_act04(usp, m)
403         struct unisig   *usp;
404         KBuffer         *m;
405 {
406         int             err;
407
408         /*
409          * Try to establish an SSCF session.
410          */
411         err = atm_cm_saal_ctl(SSCF_UNI_ESTABLISH_REQ,
412                         usp->us_conn,
413                         (void *)0);
414         if (err)
415                 panic("unisig_sigmgr_act04: SSCF_UNI_ESTABLISH_REQ");
416
417         return(0);
418 }
419
420
421 /*
422  * Signalling manager state machine action 5
423  *
424  * SSCF session on signalling channel has been reset
425  *
426  * Arguments:
427  *      usp     pointer to the UNISIG protocol control block
428  *      m       buffer pointer (may be NULL)
429  *
430  * Returns:
431  *      0       success
432  *      errno   error encountered
433  *
434  */
435 static int
436 unisig_sigmgr_act05(usp, m)
437         struct unisig   *usp;
438         KBuffer         *m;
439 {
440         struct unisig_vccb      *uvp, *vnext;
441
442         /*
443          * Log the reset
444          */
445         log(LOG_INFO, "unisig: signalling channel reset\n");
446
447         /*
448          * Notify the VC state machine of the reset
449          */
450         for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb);
451                         uvp; uvp = vnext) {
452                 vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem);
453                 (void) unisig_vc_state(usp, uvp, UNI_VC_SAAL_ESTAB,
454                                 (struct unisig_msg *) 0);
455         }
456
457         return(0);
458 }
459
460
461 /*
462  * Signalling manager state machine action 6
463  *
464  * SSCF session on signalling channel has been lost
465  *
466  * Arguments:
467  *      usp     pointer to the UNISIG protocol control block
468  *      m       buffer pointer (may be NULL)
469  *
470  * Returns:
471  *      0       success
472  *      errno   error encountered
473  *
474  */
475 static int
476 unisig_sigmgr_act06(usp, m)
477         struct unisig   *usp;
478         KBuffer         *m;
479 {
480         struct unisig_vccb      *uvp, *vnext;
481
482         /*
483          * Log the fact that the session has been lost
484          */
485         log(LOG_INFO, "unisig: signalling channel SSCF session lost\n");
486
487         /*
488          * Notify the VC state machine of the loss
489          */
490         for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb);
491                         uvp; uvp = vnext) {
492                 vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem);
493                 (void) unisig_vc_state(usp, uvp, UNI_VC_SAAL_FAIL,
494                                 (struct unisig_msg *) 0);
495         }
496
497         /*
498          * Try to restart the SSCF session
499          */
500         (void) unisig_sigmgr_act04(usp, (KBuffer *) 0);
501
502         /*
503          * Go to INIT state
504          */
505         usp->us_state = UNISIG_INIT;
506
507         return(0);
508 }
509
510
511 /*
512  * Signalling manager state machine action 7
513  *
514  * A Q.2931 signalling message has been received
515  *
516  * Arguments:
517  *      usp     pointer to the UNISIG protocol control block
518  *      m       buffer pointer (may be NULL)
519  *
520  * Returns:
521  *      0       success
522  *      errno   error encountered
523  *
524  */
525 static int
526 unisig_sigmgr_act07(usp, m)
527         struct unisig   *usp;
528         KBuffer         *m;
529 {
530         int     err;
531
532         /*
533          * Pass the Q.2931 signalling message on
534          * to the VC state machine
535          */
536         err = unisig_rcv_msg(usp, m);
537
538         return(err);
539 }
540
541
542 /*
543  * Signalling manager state machine action 8
544  *
545  * Process a CALL_CLOSED event for the signalling PVC
546  *
547  * Arguments:
548  *      usp     pointer to the UNISIG protocol control block
549  *      m       buffer pointer (may be NULL)
550  *
551  * Returns:
552  *      0       success
553  *      errno   error encountered
554  *
555  */
556 static int
557 unisig_sigmgr_act08(usp, m)
558         struct unisig   *usp;
559         KBuffer         *m;
560 {
561
562         /*
563          * Signalling manager is now incommunicado
564          */
565         if (usp->us_state != UNISIG_DETACH) {
566                 /*
567                  * Log an error and set the state to NULL if
568                  * we're not detaching
569                  */
570                 log(LOG_ERR, "unisig: signalling channel closed\n");
571                 usp->us_state = UNISIG_NULL;
572         }
573         usp->us_conn = 0;
574
575         return(0);
576 }
577
578
579 /*
580  * Signalling manager state machine action 9
581  *
582  * Not used
583  *
584  * Arguments:
585  *      usp     pointer to the UNISIG protocol control block
586  *      m       buffer pointer (may be NULL)
587  *
588  * Returns:
589  *      0       success
590  *      errno   error encountered
591  *
592  */
593 static int
594 unisig_sigmgr_act09(usp, m)
595         struct unisig   *usp;
596         KBuffer         *m;
597 {
598         log(LOG_ERR, "unisig_sigmgr_act09: unexpected action\n");
599         if (m)
600                 KB_FREEALL(m);
601         return (0);
602 }
603
604
605 /*
606  * Signalling manager state machine action 10
607  *
608  * Not used
609  *
610  * Arguments:
611  *      usp     pointer to the UNISIG protocol control block
612  *      m       buffer pointer (may be NULL)
613  *
614  * Returns:
615  *      0       success
616  *      errno   error encountered
617  *
618  */
619 static int
620 unisig_sigmgr_act10(usp, m)
621         struct unisig   *usp;
622         KBuffer         *m;
623 {
624         return(0);
625 }
626
627
628 /*
629  * Signalling manager state machine action 11
630  *
631  * Not used
632  *
633  * Arguments:
634  *      usp     pointer to the UNISIG protocol control block
635  *      m       buffer pointer (may be NULL)
636  *
637  * Returns:
638  *      0       success
639  *      errno   error encountered
640  *
641  */
642 static int
643 unisig_sigmgr_act11(usp, m)
644         struct unisig   *usp;
645         KBuffer         *m;
646 {
647         log(LOG_ERR, "unisig_sigmgr_act11: unexpected action\n");
648         if (m)
649                 KB_FREEALL(m);
650         return(0);
651 }
652
653
654 /*
655  * Signalling manager state machine action 12
656  *
657  * Not used
658  *
659  * Arguments:
660  *      usp     pointer to the UNISIG protocol control block
661  *      m       buffer pointer (may be NULL)
662  *
663  * Returns:
664  *      0       success
665  *      errno   error encountered
666  *
667  */
668 static int
669 unisig_sigmgr_act12(usp, m)
670         struct unisig   *usp;
671         KBuffer         *m;
672 {
673         log(LOG_ERR, "unisig_sigmgr_act11: unexpected action\n");
674         if (m)
675                 KB_FREEALL(m);
676         return(0);
677 }
678
679
680 /*
681  * Signalling manager state machine action 13
682  *
683  * NSAP prefix has been set
684  *
685  * Arguments:
686  *      usp     pointer to the UNISIG protocol control block
687  *      m       buffer pointer (may be NULL)
688  *
689  * Returns:
690  *      0       success
691  *      errno   error encountered
692  *
693  */
694 static int
695 unisig_sigmgr_act13(usp, m)
696         struct unisig   *usp;
697         KBuffer         *m;
698 {
699         int             err;
700         Atm_addr_pvc    *pvcp;
701
702         /*
703          * Set UNI signalling channel connection attributes
704          */
705         if (usp->us_proto == ATM_SIG_UNI30)
706                 unisig_attr.api_init = UNI_VERS_3_0;
707         else
708                 unisig_attr.api_init = UNI_VERS_3_1;
709
710         unisig_attr.nif = usp->us_pif->pif_nif;
711
712         unisig_attr.aal.v.aal5.forward_max_SDU_size = ATM_NIF_MTU;
713         unisig_attr.aal.v.aal5.backward_max_SDU_size = ATM_NIF_MTU;
714         unisig_attr.aal.v.aal5.SSCS_type = T_ATM_SSCS_SSCOP_REL;
715
716         unisig_attr.called.tag = T_ATM_PRESENT;
717         unisig_attr.called.addr.address_format = T_ATM_PVC_ADDR;
718         unisig_attr.called.addr.address_length = sizeof(Atm_addr_pvc);
719         pvcp = (Atm_addr_pvc *)unisig_attr.called.addr.address;
720         ATM_PVC_SET_VPI(pvcp, UNISIG_SIG_VPI);
721         ATM_PVC_SET_VCI(pvcp, UNISIG_SIG_VCI);
722         unisig_attr.called.subaddr.address_format = T_ATM_ABSENT;
723         unisig_attr.called.subaddr.address_length = 0;
724
725         unisig_attr.traffic.v.forward.PCR_all_traffic =
726                         usp->us_pif->pif_pcr;
727         unisig_attr.traffic.v.backward.PCR_all_traffic =
728                         usp->us_pif->pif_pcr;
729
730         /*
731          * Create UNISIG signalling channel
732          */
733         err = atm_cm_connect(&unisig_endpt, usp, &unisig_attr,
734                         &usp->us_conn);
735         if (err) {
736                 return(err);
737         }
738
739         /*
740          * Establish the SSCF session
741          */
742         err = atm_cm_saal_ctl(SSCF_UNI_ESTABLISH_REQ,
743                         usp->us_conn,
744                         (void *)0);
745         if (err)
746                 panic("unisig_sigmgr_act13: SSCF_UNI_ESTABLISH_REQ");
747
748         /*
749          * Set the new state
750          */
751         usp->us_state = UNISIG_INIT;
752
753         return(0);
754 }
755
756
757 /*
758  * Signalling manager state machine action 14
759  *
760  * Process a detach event
761  *
762  * Arguments:
763  *      usp     pointer to the UNISIG protocol control block
764  *      m       buffer pointer (may be NULL)
765  *
766  * Returns:
767  *      0       success
768  *      errno   error encountered
769  *
770  */
771 static int
772 unisig_sigmgr_act14(usp, m)
773         struct unisig   *usp;
774         KBuffer         *m;
775 {
776         int                     err;
777         struct unisig_vccb      *sig_vccb, *uvp, *vnext;
778         struct atm_pif          *pip;
779         struct t_atm_cause      cause;
780
781         /*
782          * Locate the signalling channel's VCCB
783          */
784         sig_vccb = (struct unisig_vccb *)0;
785         if (usp->us_conn && usp->us_conn->co_connvc)
786                 sig_vccb = (struct unisig_vccb *)
787                                 usp->us_conn->co_connvc->cvc_vcc;
788
789         /*
790          * Terminate all of our VCCs
791          */
792         for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb);
793                         uvp; uvp = vnext) {
794                 vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem);
795
796                 /*
797                  * Don't close the signalling VCC yet
798                  */
799                 if (uvp == sig_vccb)
800                         continue;
801
802                 /*
803                  * Close VCC and notify owner
804                  */
805                 err = unisig_clear_vcc(usp, uvp,
806                                 T_ATM_CAUSE_NORMAL_CALL_CLEARING);
807         }
808
809         /*
810          * Close the signalling channel
811          */
812         if (usp->us_conn) {
813                 cause.coding_standard = T_ATM_ITU_CODING;
814                 cause.coding_standard = T_ATM_LOC_USER;
815                 cause.coding_standard = T_ATM_CAUSE_UNSPECIFIED_NORMAL;
816                 err = atm_cm_release(usp->us_conn, &cause);
817                 if (err)
818                         panic("unisig_sigmgr_act14: close failed\n");
819         }
820
821         /*
822          * Get rid of protocol instance if there are no VCCs queued
823          */
824         pip = usp->us_pif;
825         if (Q_HEAD(usp->us_vccq, struct vccb) == NULL &&
826                         pip->pif_sigmgr) {
827                 struct sigmgr   *smp = pip->pif_sigmgr;
828                 int             s = splimp();
829
830                 pip->pif_sigmgr = NULL;
831                 pip->pif_siginst = NULL;
832                 (void) splx(s);
833
834                 UNLINK((struct siginst *)usp, struct siginst,
835                                 smp->sm_prinst, si_next);
836                 KM_FREE(usp, sizeof(struct unisig), M_DEVBUF);
837         } else {
838                 /*
839                  * Otherwise, set new signalling manager state and
840                  * wait for protocol instance to be freed during 
841                  * unisig_free processing for the last queued VCC
842                  */
843                 usp->us_state = UNISIG_DETACH;
844         }
845
846         return (0);
847 }