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