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