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