Remove compat code for anything, but DragonFly.
[dragonfly.git] / sys / netproto / atm / spans / spans_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/spans/spans_if.c,v 1.6 1999/08/28 00:48:49 peter Exp $
27  *      @(#) $DragonFly: src/sys/netproto/atm/spans/spans_if.c,v 1.8 2005/02/01 00:51:50 joerg Exp $
28  */
29
30 /*
31  * SPANS Signalling Manager
32  * ---------------------------
33  *
34  * External interfaces to SPANS manager.  Includes support for
35  * running as a loadable kernel module.
36  *
37  */
38
39 #ifndef ATM_SPANS_MODULE
40 #include "opt_atm.h"
41 #endif
42
43 #include <netproto/atm/kern_include.h>
44
45 #include "spans_xdr.h"
46 #include "spans_var.h"
47
48 /*
49  * Global variables
50  */
51 struct sp_info  spans_vcpool = {
52         "spans vcc pool",               /* si_name */
53         sizeof(struct spans_vccb),      /* si_blksiz */
54         10,                             /* si_blkcnt */
55         50                              /* si_maxallow */
56 };
57
58 struct sp_info  spans_msgpool = {
59         "spans message pool",           /* si_name */
60         sizeof(spans_msg),              /* si_blksiz */
61         10,                             /* si_blkcnt */
62         50                              /* si_maxallow */
63 };
64
65 /*
66  * Local functions
67  */
68 static int      spans_start (void);
69 static int      spans_stop (void);
70 static int      spans_attach (struct sigmgr *, struct atm_pif *);
71 static int      spans_detach (struct atm_pif *);
72 static int      spans_setup (Atm_connvc *, int *);
73 static int      spans_release (struct vccb *, int *);
74 static int      spans_accept (struct vccb *, int *);
75 static int      spans_reject (struct vccb *, int *);
76 static int      spans_ioctl (int, caddr_t, caddr_t);
77
78 /*
79  * Local variables
80  */
81 static struct sigmgr    *spans_mgr = NULL;
82
83
84 /*
85  * Initialize SPANS processing
86  *
87  * This will be called during module loading.  We'll just register
88  * the SPANS protocol descriptor and wait for a SPANS ATM interface
89  * to come online.
90  *
91  * Arguments:
92  *      none
93  *
94  * Returns:
95  *      0       startup was successful
96  *      errno   startup failed - reason indicated
97  *
98  */
99 static int
100 spans_start()
101 {
102         int     err = 0;
103
104         /*
105          * Verify software version
106          */
107         if (atm_version != ATM_VERSION) {
108                 log(LOG_ERR, "version mismatch: spans=%d.%d kernel=%d.%d\n",
109                                 ATM_VERS_MAJ(ATM_VERSION),
110                                 ATM_VERS_MIN(ATM_VERSION),
111                                 ATM_VERS_MAJ(atm_version),
112                                 ATM_VERS_MIN(atm_version));
113                 return (EINVAL);
114         }
115
116         /*
117          * Allocate protocol definition structure
118          */
119         spans_mgr = KM_ALLOC(sizeof(struct sigmgr),
120                         M_DEVBUF, M_INTWAIT | M_NULLOK);
121         if (spans_mgr == NULL) {
122                 err = ENOMEM;
123                 goto done;
124         }
125         KM_ZERO(spans_mgr, sizeof(struct sigmgr));
126
127         /*
128          * Initialize protocol invariant values
129          */
130         spans_mgr->sm_proto = ATM_SIG_SPANS;
131         spans_mgr->sm_attach = spans_attach;
132         spans_mgr->sm_detach = spans_detach;
133         spans_mgr->sm_setup = spans_setup;
134         spans_mgr->sm_release = spans_release;
135         spans_mgr->sm_accept = spans_accept;
136         spans_mgr->sm_reject = spans_reject;
137         spans_mgr->sm_free = spans_free;
138         spans_mgr->sm_ioctl = spans_ioctl;
139
140         /*
141          * Register ourselves with system
142          */
143         err = atm_sigmgr_register(spans_mgr);
144         if (err)
145                 goto done;
146
147         /*
148          * Start up Connectionless Service
149          */
150         err = spanscls_start();
151         if (err)
152                 goto done;
153
154 done:
155         return (err);
156 }
157
158
159 /*
160  * Halt SPANS processing
161  *
162  * This should be called just prior to unloading the module from
163  * memory.  All SPANS interfaces must be deregistered before the
164  * protocol can be shutdown.
165  *
166  * Arguments:
167  *      none
168  *
169  * Returns:
170  *      0       startup was successful
171  *      errno   startup failed - reason indicated
172  *
173  */
174 static int
175 spans_stop()
176 {
177         int     err = 0;
178         int     s = splnet();
179
180         /*
181          * Is protocol even set up?
182          */
183         if (spans_mgr) {
184
185                 /*
186                  * Any protocol instances still registered?
187                  */
188                 if (spans_mgr->sm_prinst) {
189
190                         /* Yes, can't stop now */
191                         err = EBUSY;
192                         goto done;
193                 }
194
195                 /*
196                  * Stop Connectionless Service
197                  */
198                 spanscls_stop();
199
200                 /*
201                  * De-register from system
202                  */
203                 err = atm_sigmgr_deregister(spans_mgr);
204
205                 /*
206                  * Free up protocol block
207                  */
208                 KM_FREE(spans_mgr, sizeof(struct sigmgr), M_DEVBUF);
209                 spans_mgr = NULL;
210
211                 /*
212                  * Free up our storage pools
213                  */
214                 atm_release_pool(&spans_vcpool);
215                 atm_release_pool(&spans_msgpool);
216         } else
217                 err = ENXIO;
218
219 done:
220         (void) splx(s);
221         return (err);
222 }
223
224
225 /*
226  * Attach a SPANS-controlled interface
227  *
228  * Each ATM physical interface must be attached with the signalling
229  * manager for the interface's signalling protocol (via the
230  * atm_sigmgr_attach function).  This function will handle the
231  * attachment for SPANS-controlled interfaces.  A new SPANS protocol
232  * instance will be created and then we'll just sit around waiting for
233  * status or connection requests.
234  *
235  * Function must be called at splnet.
236  *
237  * Arguments:
238  *      smp     pointer to SPANS signalling manager control block
239  *      pip     pointer to ATM physical interface control block
240  *
241  * Returns:
242  *      0       attach successful
243  *      errno   attach failed - reason indicated
244  *
245  */
246 static int
247 spans_attach(smp, pip)
248         struct sigmgr   *smp;
249         struct atm_pif  *pip;
250 {
251         int             err = 0, n = 0, s;
252         struct spans    *spp = NULL;
253         struct atm_nif  *np;
254
255         ATM_DEBUG2("spans_attach: smp=%p, pip=%p\n", smp, pip);
256
257         /*
258          * Count network interfaces attached to the physical interface.
259          * If there are more or less than one, we have big problems.
260          */
261         np = pip->pif_nif;
262         while (np) {
263                 n++;
264                 np = np->nif_pnext;
265         }
266         if (n != 1) {
267                 err = ETOOMANYREFS;
268                 goto done;
269         }
270
271         /*
272          * Allocate SPANS protocol instance control block
273          */
274         spp = KM_ALLOC(sizeof(struct spans),
275                         M_DEVBUF, M_INTWAIT | M_NULLOK);
276         if (spp == NULL) {
277                 err = ENOMEM;
278                 goto done;
279         }
280         KM_ZERO(spp, sizeof(struct spans));
281
282         /*
283          * Set variables in SPANS protocol instance control block
284          */
285         spp->sp_state = SPANS_INIT;
286         spp->sp_h_epoch = time_second;
287         spp->sp_s_epoch = 0;
288         spp->sp_addr.address_format = T_ATM_ABSENT;
289         spp->sp_addr.address_length = 0;
290         spp->sp_subaddr.address_format = T_ATM_ABSENT;
291         spp->sp_subaddr.address_length = 0;
292         spp->sp_probe_ct = 0;
293         spp->sp_alloc_vci = SPANS_MIN_VCI;
294         spp->sp_alloc_vpi = SPANS_VPI;
295         spp->sp_min_vci = SPANS_MIN_VCI;
296         spp->sp_max_vci = pip->pif_maxvci;
297
298         /*
299          * Link instance into manager's chain
300          */
301         LINK2TAIL((struct siginst *)spp, struct siginst, smp->sm_prinst,
302                         si_next);
303
304         /*
305          * Link in interface
306          */
307         spp->sp_pif = pip;
308         pip->pif_sigmgr = smp;
309         pip->pif_siginst = (struct siginst *) spp;
310
311         /*
312          * Kick-start the SPANS protocol
313          */
314         SPANS_TIMER(spp, 0);
315
316         /*
317          * Notify Connectionless Service
318          */
319         err = spanscls_attach(spp);
320
321         /*
322          * Log the fact that we've attached
323          */
324         if (!err)
325                 log(LOG_INFO, "spans: attached to interface %s%d\n",
326                                 pip->pif_name, pip->pif_unit);
327
328 done:
329         /*
330          * Reset our work if attach fails
331          */
332         if (err) {
333                 if (spp) {
334                         SPANS_CANCEL(spp);
335                         UNLINK((struct siginst *)spp, struct siginst,
336                                         smp->sm_prinst, si_next);
337                         KM_FREE(spp, sizeof(struct spans), M_DEVBUF);
338                 }
339                 s = splimp();
340                 pip->pif_sigmgr = NULL;
341                 pip->pif_siginst = NULL;
342                 (void) splx(s);
343         }
344
345         return (err);
346 }
347
348
349 /*
350  * Detach a SPANS-controlled interface
351  *
352  * Each ATM physical interface may be detached from its signalling
353  * manager (via the atm_sigmgr_detach function).  This function will
354  * handle the detachment for all SPANS-controlled interfaces.  All
355  * circuits will be immediately terminated.
356  *
357  * Function must be called at splnet.
358  *
359  * Arguments:
360  *      pip     pointer to ATM physical interface control block
361  *
362  * Returns:
363  *      0       detach successful
364  *      errno   detach failed - reason indicated
365  *
366  */
367 static int
368 spans_detach(pip)
369         struct atm_pif  *pip;
370 {
371         struct spans            *spp;
372         struct vccb             *vcp, *vnext;
373         Atm_connection          *cop;
374         int                     err;
375
376         ATM_DEBUG1("spans_detach: pip=%p\n", pip);
377
378         /*
379          * Get SPANS protocol instance
380          */
381         spp = (struct spans *)pip->pif_siginst;
382
383         /*
384          * Return an error if we're already detaching
385          */
386         if (spp->sp_state == SPANS_DETACH) {
387                 return(EALREADY);
388         }
389
390         /*
391          * Cancel any outstanding timer
392          */
393         SPANS_CANCEL(spp);
394
395         /*
396          * Notify Connectionless Service
397          */
398         spanscls_detach(spp);
399
400         /*
401          * Terminate all of our VCCs
402          */
403         for (vcp = Q_HEAD(spp->sp_vccq, struct vccb); vcp; vcp = vnext) {
404
405                 vnext = Q_NEXT(vcp, struct vccb, vc_sigelem);
406
407                 /*
408                  * Don't close the signalling VCC yet
409                  */
410                 if (vcp->vc_connvc && vcp->vc_connvc->cvc_conn ==
411                                 spp->sp_conn)
412                         continue;
413
414                 /*
415                  * Close VCC and notify owner
416                  */
417                 err = spans_clear_vcc(spp, (struct spans_vccb *)vcp);
418                 if (err) {
419                         log(LOG_ERR, "spans: error %d clearing VCCB %p\n",
420                                         err, vcp);
421                 }
422         }
423
424         /*
425          * Now close the SPANS signalling VCC
426          */
427         if ((cop = spp->sp_conn) != NULL) {
428                 err = atm_cm_release(cop, &spans_cause);
429                 if (err)
430                         ATM_DEBUG2(
431                                         "spans_detach: close failed for SPANS signalling channel; cop=%p, err=%d\n",
432                                         cop, err);
433         }
434         
435
436         /*
437          * Get rid of protocol instance if there are no VCCs queued
438          */
439         if (Q_HEAD(spp->sp_vccq, struct vccb) == NULL) {
440                 struct sigmgr   *smp = pip->pif_sigmgr;
441
442                 pip->pif_sigmgr = NULL;
443                 pip->pif_siginst = NULL;
444                 UNLINK((struct siginst *)spp, struct siginst,
445                                 smp->sm_prinst, si_next);
446                 KM_FREE(spp, sizeof(struct spans), M_DEVBUF);
447         } else {
448                 /*
449                  * Otherwise, wait for protocol instance to be freed
450                  * during spans_free processing for the last queued VCC.
451                  */
452                 spp->sp_state = SPANS_DETACH;
453         }
454
455         /*
456          * Log the fact that we've detached
457          */
458         log(LOG_INFO, "spans: detached from interface %s%d\n",
459                         pip->pif_name, pip->pif_unit);
460
461         return (0);
462 }
463
464
465 /*
466  * Open a SPANS ATM Connection
467  *
468  * All service user requests to open a VC connection (via
469  * atm_open_connection) over an ATM interface attached to the SPANS
470  * signalling manager are handled here.
471  *
472  * Function will be called at splnet.
473  *
474  * Arguments:
475  *      cvp     pointer to user's requested connection parameters
476  *      errp    pointer to an int for extended error information
477  *
478  * Returns:
479  *      CALL_PROCEEDING connection establishment is in progress
480  *      CALL_FAILED     connection establishment failed
481  *      CALL_CONNECTED  connection has been successfully established
482  *
483  */
484 static int
485 spans_setup(cvp, errp)
486         Atm_connvc      *cvp;
487         int             *errp;
488 {
489         struct atm_pif  *pip = cvp->cvc_attr.nif->nif_pif;
490         struct spans    *spp = (struct spans *)pip->pif_siginst;
491         int             rc = 0;
492
493         ATM_DEBUG1("spans_setup: cvp=%p\n", cvp);
494
495         /*
496          * Intialize the returned error code
497          */
498         *errp = 0;
499
500         /*
501          * Open the connection
502          */
503         switch (cvp->cvc_attr.called.addr.address_format) {
504         case T_ATM_PVC_ADDR:
505                 /*
506                  * Create a PVC
507                  */
508                 *errp = spans_open_vcc(spp, cvp);
509                 rc = (*errp ? CALL_FAILED : CALL_CONNECTED);
510                 break;
511
512         case T_ATM_SPANS_ADDR:
513
514                 /*
515                  * Create an SVC
516                  */
517                 *errp = spans_open_vcc(spp, cvp);
518                 rc = (*errp ? CALL_FAILED : CALL_PROCEEDING);
519                 break;
520
521         default:
522                 *errp = EPROTONOSUPPORT;
523                 rc = CALL_FAILED;
524         }
525
526         return (rc);
527 }
528
529
530 /*
531  * Close a SPANS ATM Connection
532  *
533  * All service user requests to terminate a previously open VC
534  * connection (via the atm_close_connection function), which is running
535  * over an interface attached to the SPANS signalling manager, are
536  * handled here.
537  *
538  * Function will be called at splnet.
539  *
540  * Arguments:
541  *      vcp     pointer to connection's VC control block
542  *      errp    pointer to an int for extended error information
543  *
544  * Returns:
545  *      CALL_PROCEEDING connection termination is in progress
546  *      CALL_FAILED     connection termination failed
547  *      CALL_CLEARED    connection has been successfully terminated
548  *
549  */
550 static int
551 spans_release(vcp, errp)
552         struct vccb     *vcp;
553         int             *errp;
554 {
555         int             rc = 0;
556         struct atm_pif  *pip = vcp->vc_pif;
557         struct spans    *spp = (struct spans *)pip->pif_siginst;
558
559         ATM_DEBUG1("spans_release: vcp=%p\n", vcp);
560
561         /*
562          * Initialize returned error code
563          */
564         *errp = 0;
565
566         /*
567          * Make sure VCC is open
568          */
569         if ((vcp->vc_sstate == SPANS_VC_NULL) ||
570                         (vcp->vc_sstate == SPANS_VC_CLOSE) ||
571                         (vcp->vc_sstate == SPANS_VC_FREE) ||
572                         (vcp->vc_ustate == VCCU_NULL) ||
573                         (vcp->vc_ustate == VCCU_CLOSED)) {
574                 *errp = EALREADY;
575                 return(CALL_FAILED);
576         }
577
578         /*
579          * Validate the connection type (PVC or SVC)
580          */
581         if (!(vcp->vc_type & (VCC_PVC | VCC_SVC))) {
582                 *errp = EPROTONOSUPPORT;
583                 return(CALL_FAILED);
584         }
585
586         /*
587          * Close the VCCB
588          */
589         *errp = spans_close_vcc(spp, (struct spans_vccb *)vcp, FALSE);
590
591         /*
592          * Set the return code
593          */
594         if (vcp->vc_type & VCC_PVC) {
595                 rc = (*errp ? CALL_FAILED : CALL_CLEARED);
596         } else {
597                 rc = (*errp ? CALL_FAILED : CALL_PROCEEDING);
598         }
599
600         return (rc);
601 }
602
603
604 /*
605  * Accept a SPANS Open from a remote host
606  *
607  * A user calls this routine (via the atm_accept_call function)
608  * after it is notified that an open request was received for it.
609  *
610  * Function will be called at splnet.
611  *
612  * Arguments:
613  *      vcp     pointer to user's VCCB
614  *      errp    pointer to an int for extended error information
615  *
616  * Returns:
617  *      CALL_PROCEEDING connection establishment is in progress
618  *      CALL_FAILED     connection establishment failed
619  *      CALL_CONNECTED  connection has been successfully established
620  *
621  */
622 static int
623 spans_accept(vcp, errp)
624         struct vccb     *vcp;
625         int             *errp;
626 {
627         struct atm_pif          *pip = vcp->vc_pif;
628         struct spans            *spp = (struct spans *)pip->pif_siginst;
629         struct spans_vccb       *svp = (struct spans_vccb *)vcp;
630
631         ATM_DEBUG1("spans_accept: vcp=%p\n", vcp);
632
633         /*
634          * Initialize the returned error code
635          */
636         *errp = 0;
637
638         /*
639          * Return an error if we're detaching
640          */
641         if (spp->sp_state == SPANS_DETACH) {
642                 *errp = ENETDOWN;
643                 ATM_DEBUG0("spans_accept: detaching\n");
644                 return(CALL_FAILED);
645         }
646
647         /*
648          * Respond to the open request
649          */
650         *errp = spans_send_open_rsp(spp, svp, SPANS_OK);
651         if (*errp) {
652                 ATM_DEBUG0("spans_accept: spans_send_open_rsp failed\n");
653                 goto failed;
654         }
655
656         /*
657          * Update the VCC states
658          */
659         svp->sv_sstate = SPANS_VC_OPEN;
660         svp->sv_ustate = VCCU_OPEN;
661
662         return(CALL_CONNECTED);
663
664 failed:
665         /*
666          * On error, free the VCCB and return CALL_FAILED
667          */
668         svp->sv_sstate = SPANS_VC_FREE;
669         svp->sv_ustate = VCCU_CLOSED;
670         DEQUEUE(svp, struct spans_vccb, sv_sigelem, spp->sp_vccq);
671         spans_free((struct vccb *)svp);
672
673         return(CALL_FAILED);
674 }
675
676
677 /*
678  * Reject a SPANS Open from a remote host
679  *
680  * A user calls this routine (via the atm_reject_call function)
681  * after it is notified that an open request was received for it.
682  *
683  * Function will be called at splnet.
684  *
685  * Arguments:
686  *      vcp     pointer to user's VCCB
687  *      errp    pointer to an int for extended error information
688  *
689  * Returns:
690  *      CALL_CLEARED    call request rejected
691  *      CALL_FAILED     call rejection failed
692  *
693  */
694 static int
695 spans_reject(vcp, errp)
696         struct vccb     *vcp;
697         int             *errp;
698 {
699         struct atm_pif          *pip = vcp->vc_pif;
700         struct spans            *spp = (struct spans *)pip->pif_siginst;
701         struct spans_vccb       *svp = (struct spans_vccb *)vcp;
702
703         ATM_DEBUG1("spans_reject: vcp=%p\n", vcp);
704
705         /*
706          * Initialize the returned error code
707          */
708         *errp = 0;
709
710         /*
711          * Return an error if we're detaching
712          */
713         if (spp->sp_state == SPANS_DETACH) {
714                 *errp = ENETDOWN;
715                 ATM_DEBUG0("spans_reject: detaching\n");
716                 return(CALL_FAILED);
717         }
718
719         ATM_DEBUG1("spans_reject: cause code is %d\n",
720                         vcp->vc_connvc->cvc_attr.cause.v.cause_value);
721
722         /*
723          * Clean up the VCCB--the connection manager will free it
724          * spans_close_vcc will send a SPANS open response
725          */
726         if ((*errp = spans_close_vcc(spp, svp, TRUE)) != 0) {
727                 ATM_DEBUG0("spans_reject: spans_close_vcc failed\n");
728                 return(CALL_FAILED);
729         }
730
731         return(CALL_CLEARED);
732 }
733
734
735 /*
736  * Abort a SPANS ATM Connection
737  *
738  * All (non-user) requests to abort a previously open VC connection (via
739  * the atm_abort_connection function), which is running over an
740  * interface attached to the SPANS signalling manager, are handled here.
741  * The VCC owner will be notified of the request, in order to initiate
742  * termination of the connection.
743  *
744  * Function will be called at splnet.
745  *
746  * Arguments:
747  *      vcp     pointer to connection's VC control block
748  *
749  * Returns:
750  *      0       connection release was succesful
751  *      errno   connection release failed - reason indicated
752  *
753  */
754 int
755 spans_abort(vcp)
756         struct vccb     *vcp;
757 {
758
759         /*
760          * Make sure VCC is available
761          */
762         if ((vcp->vc_sstate == SPANS_VC_NULL) ||
763                         (vcp->vc_sstate == SPANS_VC_CLOSE) ||
764                         (vcp->vc_sstate == SPANS_VC_FREE) ||
765                         (vcp->vc_ustate == VCCU_NULL) ||
766                         (vcp->vc_ustate == VCCU_CLOSED)) {
767                 return(EALREADY);
768         }
769
770         /*
771          * Only abort once
772          */
773         if (vcp->vc_sstate == SPANS_VC_ABORT) {
774                 return (EALREADY);
775         }
776
777         /*
778          * Cancel any timer that might be running
779          */
780         SPANS_VC_CANCEL(vcp);
781
782         /*
783          * Set immediate timer to schedule connection termination
784          */
785         vcp->vc_sstate = SPANS_VC_ABORT;
786         SPANS_VC_TIMER(vcp, 0);
787
788         return (0);
789 }
790
791
792 /*
793  * Free SPANS ATM connection resources
794  *
795  * All service user requests to free the resources of a closed
796  * VCC connection (via the atm_free_connection function), which
797  * is running over an interface attached to the SigPVC signalling
798  * manager, are handled here.
799  *
800  * Function will be called at splnet.
801  *
802  * Arguments:
803  *      vcp     pointer to connection's VC control block
804  *
805  * Returns:
806  *      0       connection free was successful
807  *      errno   connection free failed - reason indicated
808  *
809  */
810 int
811 spans_free(vcp)
812         struct vccb     *vcp;
813 {
814         struct atm_pif *pip = vcp->vc_pif;
815         struct spans *spp = (struct spans *)pip->pif_siginst;
816
817         ATM_DEBUG1("spans_free: vcp = %p\n", vcp);
818
819         /*
820          * Make sure VCC has been closed
821          */
822         if ((vcp->vc_ustate != VCCU_CLOSED) ||
823                         (vcp->vc_sstate != SPANS_VC_FREE)) {
824                 ATM_DEBUG2("spans_free: bad state, sstate=%d, ustate=%d\n",
825                                 vcp->vc_sstate, vcp->vc_ustate);
826                 return(EEXIST);
827         }
828
829         /*
830          * Remove VCCB from protocol queue
831          */
832         DEQUEUE(vcp, struct vccb, vc_sigelem, spp->sp_vccq);
833
834         /*
835          * Free VCCB storage
836          */
837         vcp->vc_ustate = VCCU_NULL;
838         vcp->vc_sstate = SPANS_VC_NULL;
839         atm_free((caddr_t)vcp);
840
841         /*
842          * If we're detaching and this was the last VCC queued,
843          * get rid of the protocol instance
844          */
845         if ((spp->sp_state == SPANS_DETACH) &&
846                         (Q_HEAD(spp->sp_vccq, struct vccb) == NULL)) {
847                 struct sigmgr   *smp = pip->pif_sigmgr;
848
849                 pip->pif_sigmgr = NULL;
850                 pip->pif_siginst = NULL;
851                 UNLINK((struct siginst *)spp, struct siginst, smp->sm_prinst,
852                                 si_next);
853                 KM_FREE(spp, sizeof(struct spans), M_DEVBUF);
854         }
855
856         return (0);
857 }
858
859
860 /*
861  * SPANS IOCTL support
862  *
863  * Function will be called at splnet.
864  *
865  * Arguments:
866  *      code    PF_ATM sub-operation code
867  *      data    pointer to code specific parameter data area
868  *      arg1    pointer to code specific argument
869  *
870  * Returns:
871  *      0       request procesed
872  *      errno   error processing request - reason indicated
873  *
874  */
875 static int
876 spans_ioctl(code, data, arg1)
877         int             code;
878         caddr_t         data;
879         caddr_t         arg1;
880 {
881         struct atmdelreq        *adp;
882         struct atminfreq        *aip;
883         struct spans            *spp;
884         struct spans_vccb       *svp;
885         struct air_vcc_rsp      rsp;
886         Atm_connection          *cop;
887         int                     buf_len, err = 0, i, vpi, vci;
888         caddr_t                 buf_addr;
889
890
891         switch (code) {
892
893         case AIOCS_DEL_PVC:
894         case AIOCS_DEL_SVC:
895                 /*
896                  * Delete a VCC
897                  */
898                 adp = (struct atmdelreq *)data;
899                 spp = (struct spans *)arg1;
900
901                 /*
902                  * Don't let a user close the SPANS signalling VC or
903                  * the SPANS CLS VC
904                  */
905                 vpi = adp->adr_pvc_vpi;
906                 vci = adp->adr_pvc_vci;
907                 if ((vpi == SPANS_SIG_VPI && vci == SPANS_SIG_VCI) ||
908                                 (vpi == SPANS_CLS_VPI &&
909                                 vci == SPANS_CLS_VCI))
910                         return(EINVAL);
911
912                 /*
913                  * Find requested VCC
914                  */
915                 for (svp = Q_HEAD(spp->sp_vccq, struct spans_vccb); svp;
916                                 svp = Q_NEXT(svp, struct spans_vccb, sv_sigelem)) {
917                         if ((svp->sv_vpi == vpi) && (svp->sv_vci == vci))
918                                 break;
919                 }
920                 if (svp == NULL)
921                         return (ENOENT);
922
923                 /*
924                  * Check VCC type
925                  */
926                 switch (code) {
927                 case AIOCS_DEL_PVC:
928                         if (!(svp->sv_type & VCC_PVC)) {
929                                 return(EINVAL);
930                         }
931                         break;
932                 case AIOCS_DEL_SVC:
933                         if (!(svp->sv_type & VCC_SVC)) {
934                                 return(EINVAL);
935                         }
936                         break;
937                 }
938
939                 /*
940                  * Schedule VCC termination
941                  */
942                 err = spans_abort((struct vccb *)svp);
943                 break;
944
945         case AIOCS_INF_VCC:
946                 /*
947                  * Return VCC information
948                  */
949                 aip = (struct atminfreq *)data;
950                 spp = (struct spans *)arg1;
951
952                 buf_addr = aip->air_buf_addr;
953                 buf_len = aip->air_buf_len;
954
955                 /*
956                  * Loop through the VCC queue
957                  */
958                 for (svp = Q_HEAD(spp->sp_vccq, struct spans_vccb); svp;
959                                 svp = Q_NEXT(svp, struct spans_vccb, sv_sigelem)) {
960                         /*
961                          * Make sure there's room in the user's buffer
962                          */
963                         if (buf_len < sizeof(rsp)) {
964                                 err = ENOSPC;
965                                 break;
966                         }
967
968                         /*
969                          * Fill out the response struct for the VCC
970                          */
971                         (void) snprintf(rsp.avp_intf,
972                                     sizeof(rsp.avp_intf), "%s%d",
973                                         spp->sp_pif->pif_name,
974                                         spp->sp_pif->pif_unit);
975                         rsp.avp_vpi = svp->sv_vpi;
976                         rsp.avp_vci = svp->sv_vci;
977                         rsp.avp_type = svp->sv_type;
978                         rsp.avp_aal = svp->sv_connvc->cvc_attr.aal.type;
979                         rsp.avp_sig_proto = svp->sv_proto;
980                         cop = svp->sv_connvc->cvc_conn;
981                         if (cop)
982                                 rsp.avp_encaps = cop->co_mpx;
983                         else
984                                 rsp.avp_encaps = 0;
985                         rsp.avp_state = svp->sv_sstate;
986                         KM_ZERO(rsp.avp_owners, sizeof(rsp.avp_owners));
987                         for (i = 0; cop && i < sizeof(rsp.avp_owners);
988                                         cop = cop->co_next,
989                                         i += T_ATM_APP_NAME_LEN+1) {
990                                 strncpy(&rsp.avp_owners[i],
991                                         cop->co_endpt->ep_getname(cop->co_toku),
992                                         T_ATM_APP_NAME_LEN);
993                         }
994                         rsp.avp_daddr.address_format = T_ATM_SPANS_ADDR;
995                         rsp.avp_daddr.address_length = 
996                                         sizeof(Atm_addr_spans);
997                         if (svp->sv_type & VCC_OUT) {
998                                 spans_addr_copy(&svp->sv_conn.con_dst,
999                                                 rsp.avp_daddr.address);
1000                         } else {
1001                                 spans_addr_copy(&svp->sv_conn.con_src,
1002                                                 rsp.avp_daddr.address);
1003                         }
1004                         rsp.avp_dsubaddr.address_format = T_ATM_ABSENT;
1005                         rsp.avp_dsubaddr.address_length = 0;
1006                         rsp.avp_ipdus = svp->sv_ipdus;
1007                         rsp.avp_opdus = svp->sv_opdus;
1008                         rsp.avp_ibytes = svp->sv_ibytes;
1009                         rsp.avp_obytes = svp->sv_obytes;
1010                         rsp.avp_ierrors = svp->sv_ierrors;
1011                         rsp.avp_oerrors = svp->sv_oerrors;
1012                         rsp.avp_tstamp = svp->sv_tstamp;
1013
1014                         /*
1015                          * Copy the response into the user's buffer
1016                          */
1017                         if ((err = copyout((caddr_t)&rsp, buf_addr,
1018                                         sizeof(rsp))) != 0)
1019                                 break;
1020                         buf_addr += sizeof(rsp);
1021                         buf_len -= sizeof(rsp);
1022                 }
1023
1024                 /*
1025                  * Update the buffer pointer and length
1026                  */
1027                 aip->air_buf_addr = buf_addr;
1028                 aip->air_buf_len = buf_len;
1029                 break;
1030
1031         case AIOCS_ADD_ARP:
1032         case AIOCS_DEL_ARP:
1033         case AIOCS_INF_ARP:
1034         case AIOCS_INF_ASV:
1035                 /*
1036                  * ARP specific ioctl's
1037                  */
1038                 err = spansarp_ioctl(code, data, arg1);
1039                 break;
1040
1041         default:
1042                 err = EOPNOTSUPP;
1043         }
1044
1045         return (err);
1046 }
1047
1048
1049 #ifdef ATM_SPANS_MODULE
1050 /*
1051  *******************************************************************
1052  *
1053  * Loadable Module Support
1054  *
1055  *******************************************************************
1056  */
1057 static int      spans_doload (void);
1058 static int      spans_dounload (void);
1059
1060 /*
1061  * Generic module load processing
1062  * 
1063  * This function is called by an OS-specific function when this
1064  * module is being loaded.
1065  *
1066  * Arguments:
1067  *      none
1068  *
1069  * Returns:
1070  *      0       load was successful 
1071  *      errno   load failed - reason indicated
1072  *
1073  */
1074 static int
1075 spans_doload()
1076 {
1077         int     err = 0;
1078
1079         /*
1080          * Start us up
1081          */
1082         err = spans_start();
1083         if (err)
1084                 /* Problems, clean up */
1085                 (void)spans_stop();
1086
1087         return (err);
1088 }
1089
1090
1091 /*
1092  * Generic module unload processing
1093  * 
1094  * This function is called by an OS-specific function when this
1095  * module is being unloaded.
1096  *
1097  * Arguments:
1098  *      none
1099  *
1100  * Returns:
1101  *      0       unload was successful 
1102  *      errno   unload failed - reason indicated
1103  *
1104  */
1105 static int
1106 spans_dounload()
1107 {
1108         int     err = 0;
1109
1110         /*
1111          * OK, try to clean up our mess
1112          */
1113         err = spans_stop();
1114
1115         return (err);
1116 }
1117
1118 #include <sys/exec.h>
1119 #include <sys/sysent.h>
1120 #include <sys/lkm.h>
1121
1122 /*
1123  * Loadable miscellaneous module description
1124  */
1125 MOD_MISC(spans);
1126
1127
1128 /*
1129  * Loadable module support "load" entry point
1130  * 
1131  * This is the routine called by the lkm driver whenever the
1132  * modload(1) command is issued for this module.
1133  *
1134  * Arguments:
1135  *      lkmtp   pointer to lkm drivers's structure
1136  *      cmd     lkm command code
1137  *
1138  * Returns:
1139  *      0       command was successful 
1140  *      errno   command failed - reason indicated
1141  *
1142  */
1143 static int
1144 spans_load(lkmtp, cmd)
1145         struct lkm_table        *lkmtp;
1146         int             cmd;
1147 {
1148         return(spans_doload());
1149 }
1150
1151
1152 /*
1153  * Loadable module support "unload" entry point
1154  * 
1155  * This is the routine called by the lkm driver whenever the
1156  * modunload(1) command is issued for this module.
1157  *
1158  * Arguments:
1159  *      lkmtp   pointer to lkm drivers's structure
1160  *      cmd     lkm command code
1161  *
1162  * Returns:
1163  *      0       command was successful 
1164  *      errno   command failed - reason indicated
1165  *
1166  */
1167 static int
1168 spans_unload(lkmtp, cmd)
1169         struct lkm_table        *lkmtp;
1170         int             cmd;
1171 {
1172         return(spans_dounload());
1173 }
1174
1175
1176 /*
1177  * Loadable module support entry point
1178  * 
1179  * This is the routine called by the lkm driver for all loadable module
1180  * functions for this driver.  This routine name must be specified
1181  * on the modload(1) command.  This routine will be called whenever the
1182  * modload(1), modunload(1) or modstat(1) commands are issued for this
1183  * module.
1184  *
1185  * Arguments:
1186  *      lkmtp   pointer to lkm drivers's structure
1187  *      cmd     lkm command code
1188  *      ver     lkm version
1189  *
1190  * Returns:
1191  *      0       command was successful 
1192  *      errno   command failed - reason indicated
1193  *
1194  */
1195 int
1196 spans_mod(lkmtp, cmd, ver)
1197         struct lkm_table        *lkmtp;
1198         int             cmd;
1199         int             ver;
1200 {
1201         MOD_DISPATCH(spans, lkmtp, cmd, ver,
1202                 spans_load, spans_unload, lkm_nullcmd);
1203 }
1204
1205 #else   /* !ATM_SPANS_MODULE */
1206
1207 /*
1208  *******************************************************************
1209  *
1210  * Kernel Compiled Module Support
1211  *
1212  *******************************************************************
1213  */
1214 static void     spans_doload (void *);
1215
1216 SYSINIT(atmspans, SI_SUB_PROTO_END, SI_ORDER_ANY, spans_doload, NULL)
1217
1218 /*
1219  * Kernel initialization
1220  * 
1221  * Arguments:
1222  *      arg     Not used
1223  *
1224  * Returns:
1225  *      none
1226  *
1227  */
1228 static void
1229 spans_doload(void *arg)
1230 {
1231         int     err = 0;
1232
1233         /*
1234          * Start us up
1235          */
1236         err = spans_start();
1237         if (err) {
1238                 /* Problems, clean up */
1239                 (void)spans_stop();
1240
1241                 log(LOG_ERR, "ATM SPANS unable to initialize (%d)!!\n", err);
1242         }
1243         return;
1244 }
1245 #endif  /* ATM_SPANS_MODULE */