More M_NOWAIT -> M_INTWAIT | M_NULLOK conversions, primarily atm and ipsec.
[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.6 2004/04/22 05:09:46 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 <netproto/atm/kern_include.h>
39
40 #include <netproto/atm/ipatm/ipatm_var.h>
41 #include <netproto/atm/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 (struct sigmgr *, struct atm_pif *);
77 static int      unisig_detach (struct atm_pif *);
78 static int      unisig_setup (Atm_connvc *, int *);
79 static int      unisig_release (struct vccb *, int *);
80 static int      unisig_accept (struct vccb *, int *);
81 static int      unisig_reject (struct vccb *, int *);
82 static int      unisig_abort (struct vccb *);
83 static int      unisig_ioctl (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 = KM_ALLOC(sizeof(struct unisig), M_DEVBUF, M_INTWAIT | M_NULLOK);
251         if (usp == NULL) {
252                 err = ENOMEM;
253                 goto done;
254         }
255         KM_ZERO(usp, sizeof(struct unisig));
256
257         /*
258          * Set state in UNISIG protocol instance control block
259          */
260         usp->us_state = UNISIG_NULL;
261         usp->us_proto = smp->sm_proto;
262
263         /*
264          * Set initial call reference allocation value
265          */
266         usp->us_cref = 1;
267
268         /*
269          * Link instance into manager's chain
270          */
271         LINK2TAIL((struct siginst *)usp, struct siginst, smp->sm_prinst,
272                         si_next);
273
274         /*
275          * Link in interface
276          */
277         usp->us_pif = pip;
278         s = splimp();
279         pip->pif_sigmgr = smp;
280         pip->pif_siginst = (struct siginst *) usp;
281         (void) splx(s);
282
283         /*
284          * Clear our ATM address.  The address will be set by user
285          * command or by registration via ILMI.
286          */
287         usp->us_addr.address_format = T_ATM_ABSENT;
288         usp->us_addr.address_length = 0;
289         usp->us_subaddr.address_format = T_ATM_ABSENT;
290         usp->us_subaddr.address_length = 0;
291
292         /*
293          * Set pointer to IP
294          */
295         usp->us_ipserv = &uniip_ipserv;
296
297         /*
298          * Kick-start the UNISIG protocol
299          */
300         UNISIG_TIMER(usp, 0);
301
302         /*
303          * Log the fact that we've attached
304          */
305         log(LOG_INFO, "unisig: attached to interface %s%d\n",
306                         pip->pif_name, pip->pif_unit);
307
308 done:
309         /*
310          * Reset our work if attach fails
311          */
312         if (err) {
313                 if (usp) {
314                         UNISIG_CANCEL(usp);
315                         UNLINK((struct siginst *)usp, struct siginst,
316                                         smp->sm_prinst, si_next);
317                         KM_FREE(usp, sizeof(struct unisig), M_DEVBUF);
318                 }
319                 s = splimp();
320                 pip->pif_sigmgr = NULL;
321                 pip->pif_siginst = NULL;
322                 (void) splx(s);
323         }
324
325         return (err);
326 }
327
328
329 /*
330  * Detach a UNISIG-controlled interface
331  *
332  * Each ATM physical interface may be detached from its signalling
333  * manager (via the atm_sigmgr_detach function).  This function will
334  * handle the detachment for all UNISIG-controlled interfaces.  All
335  * circuits will be immediately terminated.
336  *
337  * Function must be called at splnet.
338  *
339  * Arguments:
340  *      pip     pointer to ATM physical interface control block
341  *
342  * Returns:
343  *      0       detach successful
344  *      errno   detach failed - reason indicated
345  *
346  */
347 static int
348 unisig_detach(pip)
349         struct atm_pif  *pip;
350 {
351         struct unisig           *usp;
352         int                     err;
353
354         ATM_DEBUG1("unisig_detach: pip=%p\n", pip);
355
356         /*
357          * Get UNISIG protocol instance
358          */
359         usp = (struct unisig *)pip->pif_siginst;
360
361         /*
362          * Return an error if we're already detaching
363          */
364         if (usp->us_state == UNISIG_DETACH) {
365                 return(EALREADY);
366         }
367
368         /*
369          * Pass the detach event to the signalling manager
370          * state machine
371          */
372         err = unisig_sigmgr_state(usp, UNISIG_SIGMGR_DETACH,
373                         (KBuffer *)0);
374
375         /*
376          * Log the fact that we've detached
377          */
378         if (!err)
379                 log(LOG_INFO, "unisig: detached from interface %s%d\n",
380                                 pip->pif_name, pip->pif_unit);
381
382         return (0);
383 }
384
385
386 /*
387  * Open a UNISIG ATM Connection
388  *
389  * All service user requests to open a VC connection (via
390  * atm_open_connection) over an ATM interface attached to the UNISIG
391  * signalling manager are handled here.
392  *
393  * Function will be called at splnet.
394  *
395  * Arguments:
396  *      cvp     pointer to user's requested connection parameters
397  *      errp    pointer to an int for extended error information
398  *
399  * Returns:
400  *      CALL_PROCEEDING connection establishment is in progress
401  *      CALL_FAILED     connection establishment failed
402  *      CALL_CONNECTED  connection has been successfully established
403  *
404  */
405 static int
406 unisig_setup(cvp, errp)
407         Atm_connvc      *cvp;
408         int             *errp;
409 {
410         struct atm_pif  *pip = cvp->cvc_attr.nif->nif_pif;
411         struct unisig   *usp = (struct unisig *)pip->pif_siginst;
412         int             rc = 0;
413
414         ATM_DEBUG1("unisig_setup: cvp=%p\n", cvp);
415
416         /*
417          * Intialize the returned error code
418          */
419         *errp = 0;
420
421         /*
422          * Open the connection
423          */
424         switch (cvp->cvc_attr.called.addr.address_format) {
425         case T_ATM_PVC_ADDR:
426                 /*
427                  * Create a PVC
428                  */
429                 *errp = unisig_open_vcc(usp, cvp);
430                 rc = (*errp ? CALL_FAILED : CALL_CONNECTED);
431                 break;
432
433         case T_ATM_ENDSYS_ADDR:
434         case T_ATM_E164_ADDR:
435
436                 /*
437                  * Create an SVC
438                  */
439                 *errp = unisig_open_vcc(usp, cvp);
440                 rc = (*errp ? CALL_FAILED : CALL_PROCEEDING);
441                 break;
442
443         default:
444                 *errp = EPROTONOSUPPORT;
445                 rc = CALL_FAILED;
446         }
447
448         return (rc);
449 }
450
451
452 /*
453  * Close a UNISIG ATM Connection
454  *
455  * All service user requests to terminate a previously open VC
456  * connection (via the atm_close_connection function), which is running
457  * over an interface attached to the UNISIG signalling manager, are
458  * handled here.
459  *
460  * Function will be called at splnet.
461  *
462  * Arguments:
463  *      vcp     pointer to connection's VC control block
464  *      errp    pointer to an int for extended error information
465  *
466  * Returns:
467  *      CALL_PROCEEDING connection termination is in progress
468  *      CALL_FAILED     connection termination failed
469  *      CALL_CLEARED    connection has been successfully terminated
470  *
471  */
472 static int
473 unisig_release(vcp, errp)
474         struct vccb     *vcp;
475         int             *errp;
476 {
477         int             rc = 0;
478         struct atm_pif  *pip = vcp->vc_pif;
479         struct unisig   *usp = (struct unisig *)pip->pif_siginst;
480
481         ATM_DEBUG1("unisig_release: vcp=%p\n", vcp);
482
483         /*
484          * Initialize returned error code
485          */
486         *errp = 0;
487
488         /*
489          * Validate the connection type (PVC or SVC)
490          */
491         if (!(vcp->vc_type & (VCC_PVC | VCC_SVC))) {
492                 *errp = EPROTONOSUPPORT;
493                 return(CALL_FAILED);
494         }
495
496         /*
497          * Close the VCCB
498          */
499         *errp = unisig_close_vcc(usp, (struct unisig_vccb *)vcp);
500
501         /*
502          * Set the return code
503          */
504         if (*errp) {
505                 rc = CALL_FAILED;
506         } else if (vcp->vc_sstate == UNI_NULL ||
507                         vcp->vc_sstate == UNI_FREE) {
508                 rc = CALL_CLEARED;
509         } else {
510                 rc = CALL_PROCEEDING;
511         }
512
513         return (rc);
514 }
515
516
517 /*
518  * Accept a UNISIG Open from a remote host
519  *
520  * A user calls this routine (via the atm_accept_call function)
521  * after it is notified that an open request was received for it.
522  *
523  * Function will be called at splnet.
524  *
525  * Arguments:
526  *      vcp     pointer to user's VCCB
527  *      errp    pointer to an int for extended error information
528  *
529  * Returns:
530  *      CALL_PROCEEDING connection establishment is in progress
531  *      CALL_FAILED     connection establishment failed
532  *      CALL_CONNECTED  connection has been successfully established
533  *
534  */
535 static int
536 unisig_accept(vcp, errp)
537         struct vccb     *vcp;
538         int             *errp;
539 {
540         struct unisig_vccb      *uvp = (struct unisig_vccb *)vcp;
541         struct atm_pif          *pip = uvp->uv_pif;
542         struct unisig           *usp = (struct unisig *)pip->pif_siginst;
543
544         ATM_DEBUG1("unisig_accept: vcp=%p\n", vcp);
545
546         /*
547          * Initialize the returned error code
548          */
549         *errp = 0;
550
551         /*
552          * Return an error if we're detaching
553          */
554         if (usp->us_state == UNISIG_DETACH) {
555                 *errp = ENETDOWN;
556                 goto free;
557         }
558
559         /*
560          * Return an error if we lost the connection
561          */
562         if (uvp->uv_sstate == UNI_FREE) {
563                 *errp = ENETDOWN;
564                 goto free;
565         }
566
567         /*
568          * Pass the acceptance to the VC state machine
569          */
570         *errp = unisig_vc_state(usp, uvp, UNI_VC_ACCEPT_CALL,
571                         (struct unisig_msg *) 0);
572         if (*errp)
573                 goto failed;
574
575         return(CALL_PROCEEDING);
576
577 failed:
578         /*
579          * On error, free the VCCB and return CALL_FAILED
580          */
581
582 free:
583         uvp->uv_sstate = UNI_FREE;
584         uvp->uv_ustate = VCCU_CLOSED;
585         DEQUEUE(uvp, struct unisig_vccb, uv_sigelem, usp->us_vccq);
586         unisig_free((struct vccb *)uvp);
587
588         return(CALL_FAILED);
589 }
590
591
592 /*
593  * Reject a UNISIG Open from a remote host
594  *
595  * A user calls this routine (via the atm_reject_call function)
596  * after it is notified that an open request was received for it.
597  *
598  * Function will be called at splnet.
599  *
600  * Arguments:
601  *      uvp     pointer to user's VCCB
602  *      errp    pointer to an int for extended error information
603  *
604  * Returns:
605  *      CALL_CLEARED    call request rejected
606  *      CALL_FAILED     call rejection failed
607  *
608  */
609 static int
610 unisig_reject(vcp, errp)
611         struct vccb     *vcp;
612         int             *errp;
613 {
614         struct unisig_vccb      *uvp = (struct unisig_vccb *)vcp;
615         struct atm_pif          *pip = uvp->uv_pif;
616         struct unisig           *usp = (struct unisig *)pip->pif_siginst;
617
618         ATM_DEBUG1("unisig_reject: uvp=%p\n", uvp);
619
620         /*
621          * Initialize the returned error code
622          */
623         *errp = 0;
624
625
626         /*
627          * Return an error if we're detaching
628          */
629         if (usp->us_state == UNISIG_DETACH) {
630                 *errp = ENETDOWN;
631                 goto failed;
632         }
633
634         /*
635          * Call the VC state machine
636          */
637         *errp = unisig_vc_state(usp, uvp, UNI_VC_REJECT_CALL,
638                         (struct unisig_msg *) 0);
639         if (*errp)
640                 goto failed;
641
642         return(CALL_CLEARED);
643
644 failed:
645         /*
646          * On error, free the VCCB and return CALL_FAILED
647          */
648         uvp->uv_sstate = UNI_FREE;
649         uvp->uv_ustate = VCCU_CLOSED;
650         DEQUEUE(uvp, struct unisig_vccb, uv_sigelem, usp->us_vccq);
651         (void) unisig_free((struct vccb *)uvp);
652         return(CALL_FAILED);
653 }
654
655
656 /*
657  * Abort a UNISIG ATM Connection
658  *
659  * All (non-user) requests to abort a previously open VC connection (via
660  * the atm_abort_connection function), which is running over an
661  * interface attached to the UNISIG signalling manager, are handled here.
662  * The VCC owner will be notified of the request, in order to initiate
663  * termination of the connection.
664  *
665  * Function will be called at splnet.
666  *
667  * Arguments:
668  *      vcp     pointer to connection's VC control block
669  *
670  * Returns:
671  *      0       connection release was successful
672  *      errno   connection release failed - reason indicated
673  *
674  */
675 static int
676 unisig_abort(vcp)
677         struct vccb     *vcp;
678 {
679
680         ATM_DEBUG1("unisig_abort: vcp=%p\n", vcp);
681
682         /*
683          * Only abort once
684          */
685         if (vcp->vc_ustate == VCCU_ABORT) {
686                 return (EALREADY);
687         }
688
689         /*
690          * Cancel any timer that might be running
691          */
692         UNISIG_VC_CANCEL(vcp);
693
694         /*
695          * Set immediate timer to schedule connection termination
696          */
697         vcp->vc_ustate = VCCU_ABORT;
698         UNISIG_VC_TIMER(vcp, 0);
699
700         return (0);
701 }
702
703
704 /*
705  * Free UNISIG ATM connection resources
706  *
707  * All service user requests to free the resources of a closed VCC
708  * connection (via the atm_free_connection function), which is running
709  * over an interface attached to the UNISIG signalling manager, are
710  *handled here.
711  *
712  * Function will be called at splnet.
713  *
714  * Arguments:
715  *      vcp     pointer to connection's VC control block
716  *
717  * Returns:
718  *      0       connection free was successful
719  *      errno   connection free failed - reason indicated
720  *
721  */
722 int
723 unisig_free(vcp)
724         struct vccb     *vcp;
725 {
726         struct atm_pif *pip = vcp->vc_pif;
727         struct unisig *usp = (struct unisig *)pip->pif_siginst;
728
729         ATM_DEBUG1("unisig_free: vcp = %p\n", vcp);
730
731         /*
732          * Make sure VCC has been closed
733          */
734         if ((vcp->vc_ustate != VCCU_CLOSED &&
735                         vcp->vc_ustate != VCCU_ABORT) ||
736                         vcp->vc_sstate != UNI_FREE) {
737                 ATM_DEBUG2("unisig_free: bad state, sstate=%d, ustate=%d\n",
738                                 vcp->vc_sstate, vcp->vc_ustate);
739                 return(EEXIST);
740         }
741
742         /*
743          * Remove VCCB from protocol queue
744          */
745         DEQUEUE(vcp, struct vccb, vc_sigelem, usp->us_vccq);
746
747         /*
748          * Free VCCB storage
749          */
750         vcp->vc_ustate = VCCU_NULL;
751         vcp->vc_sstate = UNI_NULL;
752         atm_free((caddr_t)vcp);
753
754         /*
755          * If we're detaching and this was the last VCC queued,
756          * get rid of the protocol instance
757          */
758         if ((usp->us_state == UNISIG_DETACH) &&
759                         (Q_HEAD(usp->us_vccq, struct vccb) == NULL)) {
760                 struct sigmgr   *smp = pip->pif_sigmgr;
761                 int     s = splimp();
762
763                 pip->pif_sigmgr = NULL;
764                 pip->pif_siginst = NULL;
765                 (void) splx(s);
766
767                 UNLINK((struct siginst *)usp, struct siginst,
768                                 smp->sm_prinst, si_next);
769                 KM_FREE(usp, sizeof(struct unisig), M_DEVBUF);
770         }
771
772         return (0);
773 }
774
775
776 /*
777  * UNISIG IOCTL support
778  *
779  * Function will be called at splnet.
780  *
781  * Arguments:
782  *      code    PF_ATM sub-operation code
783  *      data    pointer to code specific parameter data area
784  *      arg1    pointer to code specific argument
785  *
786  * Returns:
787  *      0       request procesed
788  *      errno   error processing request - reason indicated
789  *
790  */
791 static int
792 unisig_ioctl(code, data, arg1)
793         int             code;
794         caddr_t         data;
795         caddr_t         arg1;
796 {
797         struct atmdelreq        *adp;
798         struct atminfreq        *aip;
799         struct atmsetreq        *asp;
800         struct unisig           *usp;
801         struct unisig_vccb      *uvp;
802         struct air_vcc_rsp      rsp;
803         struct atm_pif          *pip;
804         Atm_connection          *cop;
805         u_int                   vpi, vci;
806         int                     err = 0, buf_len, i;
807         caddr_t                 buf_addr;
808
809         ATM_DEBUG1("unisig_ioctl: code=%d\n", code);
810
811         switch (code) {
812
813         case AIOCS_DEL_PVC:
814         case AIOCS_DEL_SVC:
815                 /*
816                  * Delete a VCC
817                  */
818                 adp = (struct atmdelreq *)data;
819                 usp = (struct unisig *)arg1;
820
821                 /*
822                  * Don't let a user close the UNISIG signalling VC
823                  */
824                 vpi = adp->adr_pvc_vpi;
825                 vci = adp->adr_pvc_vci;
826                 if ((vpi == UNISIG_SIG_VPI && vci == UNISIG_SIG_VCI))
827                         return(EINVAL);
828
829                 /*
830                  * Find requested VCC
831                  */
832                 for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp;
833                                 uvp = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem)) {
834                         if ((uvp->uv_vpi == vpi) && (uvp->uv_vci == vci))
835                                 break;
836                 }
837                 if (uvp == NULL)
838                         return (ENOENT);
839
840                 /*
841                  * Check VCC type
842                  */
843                 switch (code) {
844                 case AIOCS_DEL_PVC:
845                         if (!(uvp->uv_type & VCC_PVC)) {
846                                 return(EINVAL);
847                         }
848                         break;
849                 case AIOCS_DEL_SVC:
850                         if (!(uvp->uv_type & VCC_SVC)) {
851                                 return(EINVAL);
852                         }
853                         break;
854                 }
855
856                 /*
857                  * Schedule VCC termination
858                  */
859                 unisig_cause_attr_from_user(&uvp->uv_connvc->cvc_attr,
860                                 T_ATM_CAUSE_UNSPECIFIED_NORMAL);
861                 err = unisig_abort((struct vccb *)uvp);
862                 break;
863
864         case AIOCS_INF_VCC:
865                 /*
866                  * Return VCC information
867                  */
868                 aip = (struct atminfreq *)data;
869                 usp = (struct unisig *)arg1;
870
871                 buf_addr = aip->air_buf_addr;
872                 buf_len = aip->air_buf_len;
873
874                 /*
875                  * Loop through the VCC queue
876                  */
877                 for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp;
878                                 uvp = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem)) {
879                         /*
880                          * Make sure there's room in the user's buffer
881                          */
882                         if (buf_len < sizeof(rsp)) {
883                                 err = ENOSPC;
884                                 break;
885                         }
886
887                         /*
888                          * Fill out the response struct for the VCC
889                          */
890                         (void) snprintf(rsp.avp_intf,
891                                     sizeof(rsp.avp_intf), "%s%d",
892                                         usp->us_pif->pif_name,
893                                         usp->us_pif->pif_unit);
894                         rsp.avp_vpi = uvp->uv_vpi;
895                         rsp.avp_vci = uvp->uv_vci;
896                         rsp.avp_type = uvp->uv_type;
897                         rsp.avp_aal = uvp->uv_connvc->cvc_attr.aal.type;
898                         rsp.avp_sig_proto = uvp->uv_proto;
899                         cop = uvp->uv_connvc->cvc_conn;
900                         if (cop)
901                                 rsp.avp_encaps = cop->co_mpx;
902                         else
903                                 rsp.avp_encaps = 0;
904                         rsp.avp_state = uvp->uv_sstate;
905                         if (uvp->uv_connvc->cvc_flags & CVCF_CALLER) {
906                                 rsp.avp_daddr = uvp->uv_connvc->cvc_attr.called.addr;
907                         } else {
908                                 rsp.avp_daddr = uvp->uv_connvc->cvc_attr.calling.addr;
909                         }
910                         rsp.avp_dsubaddr.address_format = T_ATM_ABSENT;
911                         rsp.avp_dsubaddr.address_length = 0;
912                         rsp.avp_ipdus = uvp->uv_ipdus;
913                         rsp.avp_opdus = uvp->uv_opdus;
914                         rsp.avp_ibytes = uvp->uv_ibytes;
915                         rsp.avp_obytes = uvp->uv_obytes;
916                         rsp.avp_ierrors = uvp->uv_ierrors;
917                         rsp.avp_oerrors = uvp->uv_oerrors;
918                         rsp.avp_tstamp = uvp->uv_tstamp;
919                         KM_ZERO(rsp.avp_owners,
920                                         sizeof(rsp.avp_owners));
921                         for (i = 0; cop && i < sizeof(rsp.avp_owners);
922                                         cop = cop->co_next,
923                                         i += T_ATM_APP_NAME_LEN+1) {
924                                 strncpy(&rsp.avp_owners[i],
925                                         cop->co_endpt->ep_getname(cop->co_toku),
926                                         T_ATM_APP_NAME_LEN);
927                         }
928
929                         /*
930                          * Copy the response into the user's buffer
931                          */
932                         if ((err = copyout((caddr_t)&rsp, buf_addr,
933                                         sizeof(rsp))) != 0)
934                                 break;
935                         buf_addr += sizeof(rsp);
936                         buf_len -= sizeof(rsp);
937                 }
938
939                 /*
940                  * Update the buffer pointer and length
941                  */
942                 aip->air_buf_addr = buf_addr;
943                 aip->air_buf_len = buf_len;
944                 break;
945
946         case AIOCS_INF_ARP:
947         case AIOCS_INF_ASV:
948         case AIOCS_SET_ASV:
949                 /*
950                  * Get ARP table information or get/set ARP server address
951                  */
952                 err = uniarp_ioctl(code, data, arg1);
953                 break;
954
955         case AIOCS_SET_PRF:
956                 /*
957                  * Set NSAP prefix
958                  */
959                 asp = (struct atmsetreq *)data;
960                 usp = (struct unisig *)arg1;
961                 pip = usp->us_pif;
962                 if (usp->us_addr.address_format != T_ATM_ABSENT) {
963                         if (KM_CMP(asp->asr_prf_pref, usp->us_addr.address,
964                                         sizeof(asp->asr_prf_pref)) != 0)
965                                 err = EALREADY;
966                         break;
967                 }
968                 usp->us_addr.address_format = T_ATM_ENDSYS_ADDR;
969                 usp->us_addr.address_length = sizeof(Atm_addr_nsap);
970                 KM_COPY(&pip->pif_macaddr,
971                         ((Atm_addr_nsap *)usp->us_addr.address)->aan_esi,
972                         sizeof(pip->pif_macaddr));
973                 KM_COPY((caddr_t) asp->asr_prf_pref,
974                         &((Atm_addr_nsap *)usp->us_addr.address)->aan_afi,
975                         sizeof(asp->asr_prf_pref));
976                 log(LOG_INFO, "uni: set address %s on interface %s\n",
977                                 unisig_addr_print(&usp->us_addr),
978                                 asp->asr_prf_intf);
979
980                 /*
981                  * Pass event to signalling manager state machine
982                  */
983                 err = unisig_sigmgr_state(usp, UNISIG_SIGMGR_ADDR_SET,
984                                 (KBuffer *) NULL);
985
986                 /*
987                  * Clean up if there was an error
988                  */
989                 if (err) {
990                         usp->us_addr.address_format = T_ATM_ABSENT;
991                         usp->us_addr.address_length = 0;
992                         break;
993                 }
994
995                 /*
996                  * Inform ARP code of new address
997                  */
998                 uniarp_ifaddr((struct siginst *)usp);
999                 break;
1000
1001         default:
1002                 err = EOPNOTSUPP;
1003         }
1004
1005         return (err);
1006 }