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