Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / netproto / atm / uni / unisig_if.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_if.c,v 1.8 2000/01/17 20:49:56 mks Exp $
27  *
28  */
29
30 /*
31  * ATM Forum UNI 3.0/3.1 Signalling Manager
32  * ----------------------------------------
33  *
34  * System interface module
35  *
36  */
37
38 #include <netatm/kern_include.h>
39
40 #include <netatm/ipatm/ipatm_var.h>
41 #include <netatm/ipatm/ipatm_serv.h>
42 #include <netatm/uni/uniip_var.h>
43
44 #include <netatm/uni/unisig.h>
45 #include <netatm/uni/unisig_var.h>
46 #include <netatm/uni/unisig_msg.h>
47
48 #ifndef lint
49 __RCSID("@(#) $FreeBSD: src/sys/netatm/uni/unisig_if.c,v 1.8 2000/01/17 20:49:56 mks Exp $");
50 #endif
51
52
53 /*
54  * Global variables
55  */
56 struct sp_info  unisig_vcpool = {
57         "unisig vcc pool",              /* si_name */
58         sizeof(struct unisig_vccb),     /* si_blksiz */
59         10,                             /* si_blkcnt */
60         50                              /* si_maxallow */
61 };
62
63 struct sp_info  unisig_msgpool = {
64         "unisig message pool",          /* si_name */
65         sizeof(struct unisig_msg),      /* si_blksiz */
66         10,                             /* si_blkcnt */
67         50                              /* si_maxallow */
68 };
69
70 struct sp_info  unisig_iepool = {
71         "unisig ie pool",               /* si_name */
72         sizeof(struct ie_generic),      /* si_blksiz */
73         10,                             /* si_blkcnt */
74         50                              /* si_maxallow */
75 };
76
77
78 /*
79  * Local functions
80  */
81 static int      unisig_attach __P((struct sigmgr *, struct atm_pif *));
82 static int      unisig_detach __P((struct atm_pif *));
83 static int      unisig_setup __P((Atm_connvc *, int *));
84 static int      unisig_release __P((struct vccb *, int *));
85 static int      unisig_accept __P((struct vccb *, int *));
86 static int      unisig_reject __P((struct vccb *, int *));
87 static int      unisig_abort __P((struct vccb *));
88 static int      unisig_ioctl __P((int, caddr_t, caddr_t));
89
90
91 /*
92  * Local variables
93  */
94 static struct sigmgr    unisig_mgr30 = {
95         NULL,
96         ATM_SIG_UNI30,
97         NULL,
98         unisig_attach,
99         unisig_detach,
100         unisig_setup,
101         unisig_accept,
102         unisig_reject,
103         unisig_release,
104         unisig_free,
105         unisig_ioctl
106 };
107
108 static struct sigmgr    unisig_mgr31 = {
109         NULL,
110         ATM_SIG_UNI31,
111         NULL,
112         unisig_attach,
113         unisig_detach,
114         unisig_setup,
115         unisig_accept,
116         unisig_reject,
117         unisig_release,
118         unisig_free,
119         unisig_ioctl
120 };
121
122
123 /*
124  * Initialize UNISIG processing
125  *
126  * This will be called during module loading.  We'll just register
127  * the UNISIG protocol descriptor and wait for a UNISIG ATM interface
128  * to come online.
129  *
130  * Arguments:
131  *      none
132  *
133  * Returns:
134  *      0       startup was successful
135  *      errno   startup failed - reason indicated
136  *
137  */
138 int
139 unisig_start()
140 {
141         int     err = 0;
142
143         /*      
144          * Verify software version
145          */     
146         if (atm_version != ATM_VERSION) { 
147                 log(LOG_ERR, "version mismatch: unisig=%d.%d kernel=%d.%d\n", 
148                                 ATM_VERS_MAJ(ATM_VERSION),
149                                 ATM_VERS_MIN(ATM_VERSION),
150                                 ATM_VERS_MAJ(atm_version),
151                                 ATM_VERS_MIN(atm_version));
152                 return (EINVAL);
153         }
154
155         /*
156          * Register ourselves with system
157          */
158         err = atm_sigmgr_register(&unisig_mgr30);
159         if (err)
160                 goto done;
161
162         err = atm_sigmgr_register(&unisig_mgr31);
163
164 done:
165         return (err);
166 }
167
168
169 /*
170  * Halt UNISIG processing
171  *
172  * This should be called just prior to unloading the module from
173  * memory.  All UNISIG interfaces must be deregistered before the
174  * protocol can be shutdown.
175  *
176  * Arguments:
177  *      none
178  *
179  * Returns:
180  *      0       startup was successful
181  *      errno   startup failed - reason indicated
182  *
183  */
184 int
185 unisig_stop()
186 {
187         int     err = 0;
188         int     s = splnet();
189
190
191         /*
192          * Any protocol instances still registered?
193          */
194         if ((unisig_mgr30.sm_prinst != NULL) ||
195             (unisig_mgr31.sm_prinst != NULL)) {
196
197                 /* Yes, can't stop now */
198                 err = EBUSY;
199                 goto done;
200         }
201
202         /*
203          * De-register from system
204          */
205         (void) atm_sigmgr_deregister(&unisig_mgr30);
206         (void) atm_sigmgr_deregister(&unisig_mgr31);
207
208         /*
209          * Free up our storage pools
210          */
211         atm_release_pool(&unisig_vcpool);
212         atm_release_pool(&unisig_msgpool);
213         atm_release_pool(&unisig_iepool);
214
215 done:
216         (void) splx(s);
217         return (err);
218 }
219
220
221 /*
222  * Attach a UNISIG-controlled interface
223  *
224  * Each ATM physical interface must be attached with the signalling
225  * manager for the interface's signalling protocol (via the
226  * atm_sigmgr_attach function).  This function will handle the
227  * attachment for UNISIG-controlled interfaces.  A new UNISIG protocol
228  * instance will be created and then we'll just sit around waiting for
229  * status or connection requests.
230  *
231  * Function must be called at splnet.
232  *
233  * Arguments:
234  *      smp     pointer to UNISIG signalling manager control block
235  *      pip     pointer to ATM physical interface control block
236  *
237  * Returns:
238  *      0       attach successful
239  *      errno   attach failed - reason indicated
240  *
241  */
242 static int
243 unisig_attach(smp, pip)
244         struct sigmgr   *smp;
245         struct atm_pif  *pip;
246 {
247         int                     err = 0, s;
248         struct unisig           *usp = NULL;
249
250         ATM_DEBUG2("unisig_attach: smp=%p, pip=%p\n", smp, pip);
251
252         /*
253          * Allocate UNISIG protocol instance control block
254          */
255         usp = (struct unisig *)
256                         KM_ALLOC(sizeof(struct unisig), M_DEVBUF, M_NOWAIT);
257         if (usp == NULL) {
258                 err = ENOMEM;
259                 goto done;
260         }
261         KM_ZERO(usp, sizeof(struct unisig));
262
263         /*
264          * Set state in UNISIG protocol instance control block
265          */
266         usp->us_state = UNISIG_NULL;
267         usp->us_proto = smp->sm_proto;
268
269         /*
270          * Set initial call reference allocation value
271          */
272         usp->us_cref = 1;
273
274         /*
275          * Link instance into manager's chain
276          */
277         LINK2TAIL((struct siginst *)usp, struct siginst, smp->sm_prinst,
278                         si_next);
279
280         /*
281          * Link in interface
282          */
283         usp->us_pif = pip;
284         s = splimp();
285         pip->pif_sigmgr = smp;
286         pip->pif_siginst = (struct siginst *) usp;
287         (void) splx(s);
288
289         /*
290          * Clear our ATM address.  The address will be set by user
291          * command or by registration via ILMI.
292          */
293         usp->us_addr.address_format = T_ATM_ABSENT;
294         usp->us_addr.address_length = 0;
295         usp->us_subaddr.address_format = T_ATM_ABSENT;
296         usp->us_subaddr.address_length = 0;
297
298         /*
299          * Set pointer to IP
300          */
301         usp->us_ipserv = &uniip_ipserv;
302
303         /*
304          * Kick-start the UNISIG protocol
305          */
306         UNISIG_TIMER(usp, 0);
307
308         /*
309          * Log the fact that we've attached
310          */
311         log(LOG_INFO, "unisig: attached to interface %s%d\n",
312                         pip->pif_name, pip->pif_unit);
313
314 done:
315         /*
316          * Reset our work if attach fails
317          */
318         if (err) {
319                 if (usp) {
320                         UNISIG_CANCEL(usp);
321                         UNLINK((struct siginst *)usp, struct siginst,
322                                         smp->sm_prinst, si_next);
323                         KM_FREE(usp, sizeof(struct unisig), M_DEVBUF);
324                 }
325                 s = splimp();
326                 pip->pif_sigmgr = NULL;
327                 pip->pif_siginst = NULL;
328                 (void) splx(s);
329         }
330
331         return (err);
332 }
333
334
335 /*
336  * Detach a UNISIG-controlled interface
337  *
338  * Each ATM physical interface may be detached from its signalling
339  * manager (via the atm_sigmgr_detach function).  This function will
340  * handle the detachment for all UNISIG-controlled interfaces.  All
341  * circuits will be immediately terminated.
342  *
343  * Function must be called at splnet.
344  *
345  * Arguments:
346  *      pip     pointer to ATM physical interface control block
347  *
348  * Returns:
349  *      0       detach successful
350  *      errno   detach failed - reason indicated
351  *
352  */
353 static int
354 unisig_detach(pip)
355         struct atm_pif  *pip;
356 {
357         struct unisig           *usp;
358         int                     err;
359
360         ATM_DEBUG1("unisig_detach: pip=%p\n", pip);
361
362         /*
363          * Get UNISIG protocol instance
364          */
365         usp = (struct unisig *)pip->pif_siginst;
366
367         /*
368          * Return an error if we're already detaching
369          */
370         if (usp->us_state == UNISIG_DETACH) {
371                 return(EALREADY);
372         }
373
374         /*
375          * Pass the detach event to the signalling manager
376          * state machine
377          */
378         err = unisig_sigmgr_state(usp, UNISIG_SIGMGR_DETACH,
379                         (KBuffer *)0);
380
381         /*
382          * Log the fact that we've detached
383          */
384         if (!err)
385                 log(LOG_INFO, "unisig: detached from interface %s%d\n",
386                                 pip->pif_name, pip->pif_unit);
387
388         return (0);
389 }
390
391
392 /*
393  * Open a UNISIG ATM Connection
394  *
395  * All service user requests to open a VC connection (via
396  * atm_open_connection) over an ATM interface attached to the UNISIG
397  * signalling manager are handled here.
398  *
399  * Function will be called at splnet.
400  *
401  * Arguments:
402  *      cvp     pointer to user's requested connection parameters
403  *      errp    pointer to an int for extended error information
404  *
405  * Returns:
406  *      CALL_PROCEEDING connection establishment is in progress
407  *      CALL_FAILED     connection establishment failed
408  *      CALL_CONNECTED  connection has been successfully established
409  *
410  */
411 static int
412 unisig_setup(cvp, errp)
413         Atm_connvc      *cvp;
414         int             *errp;
415 {
416         struct atm_pif  *pip = cvp->cvc_attr.nif->nif_pif;
417         struct unisig   *usp = (struct unisig *)pip->pif_siginst;
418         int             rc = 0;
419
420         ATM_DEBUG1("unisig_setup: cvp=%p\n", cvp);
421
422         /*
423          * Intialize the returned error code
424          */
425         *errp = 0;
426
427         /*
428          * Open the connection
429          */
430         switch (cvp->cvc_attr.called.addr.address_format) {
431         case T_ATM_PVC_ADDR:
432                 /*
433                  * Create a PVC
434                  */
435                 *errp = unisig_open_vcc(usp, cvp);
436                 rc = (*errp ? CALL_FAILED : CALL_CONNECTED);
437                 break;
438
439         case T_ATM_ENDSYS_ADDR:
440         case T_ATM_E164_ADDR:
441
442                 /*
443                  * Create an SVC
444                  */
445                 *errp = unisig_open_vcc(usp, cvp);
446                 rc = (*errp ? CALL_FAILED : CALL_PROCEEDING);
447                 break;
448
449         default:
450                 *errp = EPROTONOSUPPORT;
451                 rc = CALL_FAILED;
452         }
453
454         return (rc);
455 }
456
457
458 /*
459  * Close a UNISIG ATM Connection
460  *
461  * All service user requests to terminate a previously open VC
462  * connection (via the atm_close_connection function), which is running
463  * over an interface attached to the UNISIG signalling manager, are
464  * handled here.
465  *
466  * Function will be called at splnet.
467  *
468  * Arguments:
469  *      vcp     pointer to connection's VC control block
470  *      errp    pointer to an int for extended error information
471  *
472  * Returns:
473  *      CALL_PROCEEDING connection termination is in progress
474  *      CALL_FAILED     connection termination failed
475  *      CALL_CLEARED    connection has been successfully terminated
476  *
477  */
478 static int
479 unisig_release(vcp, errp)
480         struct vccb     *vcp;
481         int             *errp;
482 {
483         int             rc = 0;
484         struct atm_pif  *pip = vcp->vc_pif;
485         struct unisig   *usp = (struct unisig *)pip->pif_siginst;
486
487         ATM_DEBUG1("unisig_release: vcp=%p\n", vcp);
488
489         /*
490          * Initialize returned error code
491          */
492         *errp = 0;
493
494         /*
495          * Validate the connection type (PVC or SVC)
496          */
497         if (!(vcp->vc_type & (VCC_PVC | VCC_SVC))) {
498                 *errp = EPROTONOSUPPORT;
499                 return(CALL_FAILED);
500         }
501
502         /*
503          * Close the VCCB
504          */
505         *errp = unisig_close_vcc(usp, (struct unisig_vccb *)vcp);
506
507         /*
508          * Set the return code
509          */
510         if (*errp) {
511                 rc = CALL_FAILED;
512         } else if (vcp->vc_sstate == UNI_NULL ||
513                         vcp->vc_sstate == UNI_FREE) {
514                 rc = CALL_CLEARED;
515         } else {
516                 rc = CALL_PROCEEDING;
517         }
518
519         return (rc);
520 }
521
522
523 /*
524  * Accept a UNISIG Open from a remote host
525  *
526  * A user calls this routine (via the atm_accept_call function)
527  * after it is notified that an open request was received for it.
528  *
529  * Function will be called at splnet.
530  *
531  * Arguments:
532  *      vcp     pointer to user's VCCB
533  *      errp    pointer to an int for extended error information
534  *
535  * Returns:
536  *      CALL_PROCEEDING connection establishment is in progress
537  *      CALL_FAILED     connection establishment failed
538  *      CALL_CONNECTED  connection has been successfully established
539  *
540  */
541 static int
542 unisig_accept(vcp, errp)
543         struct vccb     *vcp;
544         int             *errp;
545 {
546         struct unisig_vccb      *uvp = (struct unisig_vccb *)vcp;
547         struct atm_pif          *pip = uvp->uv_pif;
548         struct unisig           *usp = (struct unisig *)pip->pif_siginst;
549
550         ATM_DEBUG1("unisig_accept: vcp=%p\n", vcp);
551
552         /*
553          * Initialize the returned error code
554          */
555         *errp = 0;
556
557         /*
558          * Return an error if we're detaching
559          */
560         if (usp->us_state == UNISIG_DETACH) {
561                 *errp = ENETDOWN;
562                 goto free;
563         }
564
565         /*
566          * Return an error if we lost the connection
567          */
568         if (uvp->uv_sstate == UNI_FREE) {
569                 *errp = ENETDOWN;
570                 goto free;
571         }
572
573         /*
574          * Pass the acceptance to the VC state machine
575          */
576         *errp = unisig_vc_state(usp, uvp, UNI_VC_ACCEPT_CALL,
577                         (struct unisig_msg *) 0);
578         if (*errp)
579                 goto failed;
580
581         return(CALL_PROCEEDING);
582
583 failed:
584         /*
585          * On error, free the VCCB and return CALL_FAILED
586          */
587
588 free:
589         uvp->uv_sstate = UNI_FREE;
590         uvp->uv_ustate = VCCU_CLOSED;
591         DEQUEUE(uvp, struct unisig_vccb, uv_sigelem, usp->us_vccq);
592         unisig_free((struct vccb *)uvp);
593
594         return(CALL_FAILED);
595 }
596
597
598 /*
599  * Reject a UNISIG Open from a remote host
600  *
601  * A user calls this routine (via the atm_reject_call function)
602  * after it is notified that an open request was received for it.
603  *
604  * Function will be called at splnet.
605  *
606  * Arguments:
607  *      uvp     pointer to user's VCCB
608  *      errp    pointer to an int for extended error information
609  *
610  * Returns:
611  *      CALL_CLEARED    call request rejected
612  *      CALL_FAILED     call rejection failed
613  *
614  */
615 static int
616 unisig_reject(vcp, errp)
617         struct vccb     *vcp;
618         int             *errp;
619 {
620         struct unisig_vccb      *uvp = (struct unisig_vccb *)vcp;
621         struct atm_pif          *pip = uvp->uv_pif;
622         struct unisig           *usp = (struct unisig *)pip->pif_siginst;
623
624         ATM_DEBUG1("unisig_reject: uvp=%p\n", uvp);
625
626         /*
627          * Initialize the returned error code
628          */
629         *errp = 0;
630
631
632         /*
633          * Return an error if we're detaching
634          */
635         if (usp->us_state == UNISIG_DETACH) {
636                 *errp = ENETDOWN;
637                 goto failed;
638         }
639
640         /*
641          * Call the VC state machine
642          */
643         *errp = unisig_vc_state(usp, uvp, UNI_VC_REJECT_CALL,
644                         (struct unisig_msg *) 0);
645         if (*errp)
646                 goto failed;
647
648         return(CALL_CLEARED);
649
650 failed:
651         /*
652          * On error, free the VCCB and return CALL_FAILED
653          */
654         uvp->uv_sstate = UNI_FREE;
655         uvp->uv_ustate = VCCU_CLOSED;
656         DEQUEUE(uvp, struct unisig_vccb, uv_sigelem, usp->us_vccq);
657         (void) unisig_free((struct vccb *)uvp);
658         return(CALL_FAILED);
659 }
660
661
662 /*
663  * Abort a UNISIG ATM Connection
664  *
665  * All (non-user) requests to abort a previously open VC connection (via
666  * the atm_abort_connection function), which is running over an
667  * interface attached to the UNISIG signalling manager, are handled here.
668  * The VCC owner will be notified of the request, in order to initiate
669  * termination of the connection.
670  *
671  * Function will be called at splnet.
672  *
673  * Arguments:
674  *      vcp     pointer to connection's VC control block
675  *
676  * Returns:
677  *      0       connection release was successful
678  *      errno   connection release failed - reason indicated
679  *
680  */
681 static int
682 unisig_abort(vcp)
683         struct vccb     *vcp;
684 {
685
686         ATM_DEBUG1("unisig_abort: vcp=%p\n", vcp);
687
688         /*
689          * Only abort once
690          */
691         if (vcp->vc_ustate == VCCU_ABORT) {
692                 return (EALREADY);
693         }
694
695         /*
696          * Cancel any timer that might be running
697          */
698         UNISIG_VC_CANCEL(vcp);
699
700         /*
701          * Set immediate timer to schedule connection termination
702          */
703         vcp->vc_ustate = VCCU_ABORT;
704         UNISIG_VC_TIMER(vcp, 0);
705
706         return (0);
707 }
708
709
710 /*
711  * Free UNISIG ATM connection resources
712  *
713  * All service user requests to free the resources of a closed VCC
714  * connection (via the atm_free_connection function), which is running
715  * over an interface attached to the UNISIG signalling manager, are
716  *handled here.
717  *
718  * Function will be called at splnet.
719  *
720  * Arguments:
721  *      vcp     pointer to connection's VC control block
722  *
723  * Returns:
724  *      0       connection free was successful
725  *      errno   connection free failed - reason indicated
726  *
727  */
728 int
729 unisig_free(vcp)
730         struct vccb     *vcp;
731 {
732         struct atm_pif *pip = vcp->vc_pif;
733         struct unisig *usp = (struct unisig *)pip->pif_siginst;
734
735         ATM_DEBUG1("unisig_free: vcp = %p\n", vcp);
736
737         /*
738          * Make sure VCC has been closed
739          */
740         if ((vcp->vc_ustate != VCCU_CLOSED &&
741                         vcp->vc_ustate != VCCU_ABORT) ||
742                         vcp->vc_sstate != UNI_FREE) {
743                 ATM_DEBUG2("unisig_free: bad state, sstate=%d, ustate=%d\n",
744                                 vcp->vc_sstate, vcp->vc_ustate);
745                 return(EEXIST);
746         }
747
748         /*
749          * Remove VCCB from protocol queue
750          */
751         DEQUEUE(vcp, struct vccb, vc_sigelem, usp->us_vccq);
752
753         /*
754          * Free VCCB storage
755          */
756         vcp->vc_ustate = VCCU_NULL;
757         vcp->vc_sstate = UNI_NULL;
758         atm_free((caddr_t)vcp);
759
760         /*
761          * If we're detaching and this was the last VCC queued,
762          * get rid of the protocol instance
763          */
764         if ((usp->us_state == UNISIG_DETACH) &&
765                         (Q_HEAD(usp->us_vccq, struct vccb) == NULL)) {
766                 struct sigmgr   *smp = pip->pif_sigmgr;
767                 int     s = splimp();
768
769                 pip->pif_sigmgr = NULL;
770                 pip->pif_siginst = NULL;
771                 (void) splx(s);
772
773                 UNLINK((struct siginst *)usp, struct siginst,
774                                 smp->sm_prinst, si_next);
775                 KM_FREE(usp, sizeof(struct unisig), M_DEVBUF);
776         }
777
778         return (0);
779 }
780
781
782 /*
783  * UNISIG IOCTL support
784  *
785  * Function will be called at splnet.
786  *
787  * Arguments:
788  *      code    PF_ATM sub-operation code
789  *      data    pointer to code specific parameter data area
790  *      arg1    pointer to code specific argument
791  *
792  * Returns:
793  *      0       request procesed
794  *      errno   error processing request - reason indicated
795  *
796  */
797 static int
798 unisig_ioctl(code, data, arg1)
799         int             code;
800         caddr_t         data;
801         caddr_t         arg1;
802 {
803         struct atmdelreq        *adp;
804         struct atminfreq        *aip;
805         struct atmsetreq        *asp;
806         struct unisig           *usp;
807         struct unisig_vccb      *uvp;
808         struct air_vcc_rsp      rsp;
809         struct atm_pif          *pip;
810         Atm_connection          *cop;
811         u_int                   vpi, vci;
812         int                     err = 0, buf_len, i;
813         caddr_t                 buf_addr;
814
815         ATM_DEBUG1("unisig_ioctl: code=%d\n", code);
816
817         switch (code) {
818
819         case AIOCS_DEL_PVC:
820         case AIOCS_DEL_SVC:
821                 /*
822                  * Delete a VCC
823                  */
824                 adp = (struct atmdelreq *)data;
825                 usp = (struct unisig *)arg1;
826
827                 /*
828                  * Don't let a user close the UNISIG signalling VC
829                  */
830                 vpi = adp->adr_pvc_vpi;
831                 vci = adp->adr_pvc_vci;
832                 if ((vpi == UNISIG_SIG_VPI && vci == UNISIG_SIG_VCI))
833                         return(EINVAL);
834
835                 /*
836                  * Find requested VCC
837                  */
838                 for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp;
839                                 uvp = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem)) {
840                         if ((uvp->uv_vpi == vpi) && (uvp->uv_vci == vci))
841                                 break;
842                 }
843                 if (uvp == NULL)
844                         return (ENOENT);
845
846                 /*
847                  * Check VCC type
848                  */
849                 switch (code) {
850                 case AIOCS_DEL_PVC:
851                         if (!(uvp->uv_type & VCC_PVC)) {
852                                 return(EINVAL);
853                         }
854                         break;
855                 case AIOCS_DEL_SVC:
856                         if (!(uvp->uv_type & VCC_SVC)) {
857                                 return(EINVAL);
858                         }
859                         break;
860                 }
861
862                 /*
863                  * Schedule VCC termination
864                  */
865                 unisig_cause_attr_from_user(&uvp->uv_connvc->cvc_attr,
866                                 T_ATM_CAUSE_UNSPECIFIED_NORMAL);
867                 err = unisig_abort((struct vccb *)uvp);
868                 break;
869
870         case AIOCS_INF_VCC:
871                 /*
872                  * Return VCC information
873                  */
874                 aip = (struct atminfreq *)data;
875                 usp = (struct unisig *)arg1;
876
877                 buf_addr = aip->air_buf_addr;
878                 buf_len = aip->air_buf_len;
879
880                 /*
881                  * Loop through the VCC queue
882                  */
883                 for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp;
884                                 uvp = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem)) {
885                         /*
886                          * Make sure there's room in the user's buffer
887                          */
888                         if (buf_len < sizeof(rsp)) {
889                                 err = ENOSPC;
890                                 break;
891                         }
892
893                         /*
894                          * Fill out the response struct for the VCC
895                          */
896                         (void) snprintf(rsp.avp_intf,
897                                     sizeof(rsp.avp_intf), "%s%d",
898                                         usp->us_pif->pif_name,
899                                         usp->us_pif->pif_unit);
900                         rsp.avp_vpi = uvp->uv_vpi;
901                         rsp.avp_vci = uvp->uv_vci;
902                         rsp.avp_type = uvp->uv_type;
903                         rsp.avp_aal = uvp->uv_connvc->cvc_attr.aal.type;
904                         rsp.avp_sig_proto = uvp->uv_proto;
905                         cop = uvp->uv_connvc->cvc_conn;
906                         if (cop)
907                                 rsp.avp_encaps = cop->co_mpx;
908                         else
909                                 rsp.avp_encaps = 0;
910                         rsp.avp_state = uvp->uv_sstate;
911                         if (uvp->uv_connvc->cvc_flags & CVCF_CALLER) {
912                                 rsp.avp_daddr = uvp->uv_connvc->cvc_attr.called.addr;
913                         } else {
914                                 rsp.avp_daddr = uvp->uv_connvc->cvc_attr.calling.addr;
915                         }
916                         rsp.avp_dsubaddr.address_format = T_ATM_ABSENT;
917                         rsp.avp_dsubaddr.address_length = 0;
918                         rsp.avp_ipdus = uvp->uv_ipdus;
919                         rsp.avp_opdus = uvp->uv_opdus;
920                         rsp.avp_ibytes = uvp->uv_ibytes;
921                         rsp.avp_obytes = uvp->uv_obytes;
922                         rsp.avp_ierrors = uvp->uv_ierrors;
923                         rsp.avp_oerrors = uvp->uv_oerrors;
924                         rsp.avp_tstamp = uvp->uv_tstamp;
925                         KM_ZERO(rsp.avp_owners,
926                                         sizeof(rsp.avp_owners));
927                         for (i = 0; cop && i < sizeof(rsp.avp_owners);
928                                         cop = cop->co_next,
929                                         i += T_ATM_APP_NAME_LEN+1) {
930                                 strncpy(&rsp.avp_owners[i],
931                                         cop->co_endpt->ep_getname(cop->co_toku),
932                                         T_ATM_APP_NAME_LEN);
933                         }
934
935                         /*
936                          * Copy the response into the user's buffer
937                          */
938                         if ((err = copyout((caddr_t)&rsp, buf_addr,
939                                         sizeof(rsp))) != 0)
940                                 break;
941                         buf_addr += sizeof(rsp);
942                         buf_len -= sizeof(rsp);
943                 }
944
945                 /*
946                  * Update the buffer pointer and length
947                  */
948                 aip->air_buf_addr = buf_addr;
949                 aip->air_buf_len = buf_len;
950                 break;
951
952         case AIOCS_INF_ARP:
953         case AIOCS_INF_ASV:
954         case AIOCS_SET_ASV:
955                 /*
956                  * Get ARP table information or get/set ARP server address
957                  */
958                 err = uniarp_ioctl(code, data, arg1);
959                 break;
960
961         case AIOCS_SET_PRF:
962                 /*
963                  * Set NSAP prefix
964                  */
965                 asp = (struct atmsetreq *)data;
966                 usp = (struct unisig *)arg1;
967                 pip = usp->us_pif;
968                 if (usp->us_addr.address_format != T_ATM_ABSENT) {
969                         if (KM_CMP(asp->asr_prf_pref, usp->us_addr.address,
970                                         sizeof(asp->asr_prf_pref)) != 0)
971                                 err = EALREADY;
972                         break;
973                 }
974                 usp->us_addr.address_format = T_ATM_ENDSYS_ADDR;
975                 usp->us_addr.address_length = sizeof(Atm_addr_nsap);
976                 KM_COPY(&pip->pif_macaddr,
977                         ((Atm_addr_nsap *)usp->us_addr.address)->aan_esi,
978                         sizeof(pip->pif_macaddr));
979                 KM_COPY((caddr_t) asp->asr_prf_pref,
980                         &((Atm_addr_nsap *)usp->us_addr.address)->aan_afi,
981                         sizeof(asp->asr_prf_pref));
982                 log(LOG_INFO, "uni: set address %s on interface %s\n",
983                                 unisig_addr_print(&usp->us_addr),
984                                 asp->asr_prf_intf);
985
986                 /*
987                  * Pass event to signalling manager state machine
988                  */
989                 err = unisig_sigmgr_state(usp, UNISIG_SIGMGR_ADDR_SET,
990                                 (KBuffer *) NULL);
991
992                 /*
993                  * Clean up if there was an error
994                  */
995                 if (err) {
996                         usp->us_addr.address_format = T_ATM_ABSENT;
997                         usp->us_addr.address_length = 0;
998                         break;
999                 }
1000
1001                 /*
1002                  * Inform ARP code of new address
1003                  */
1004                 uniarp_ifaddr((struct siginst *)usp);
1005                 break;
1006
1007         default:
1008                 err = EOPNOTSUPP;
1009         }
1010
1011         return (err);
1012 }