Remove compat code for anything, but DragonFly.
[dragonfly.git] / sys / netproto / atm / sigpvc / sigpvc_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/sigpvc/sigpvc_if.c,v 1.7 2000/01/17 20:49:46 mks Exp $
27  *      @(#) $DragonFly: src/sys/netproto/atm/sigpvc/sigpvc_if.c,v 1.8 2005/02/01 00:51:50 joerg Exp $
28  */
29
30 /*
31  * PVC-only Signalling Manager
32  * ---------------------------
33  *
34  * External interfaces to SigPVC manager.  Includes support for 
35  * running as a loadable kernel module.
36  *
37  */
38
39 #ifndef ATM_SIGPVC_MODULE
40 #include "opt_atm.h"
41 #endif
42
43 #include <netproto/atm/kern_include.h>
44
45 #include "sigpvc_var.h"
46
47 /*
48  * Global variables
49  */
50 struct sp_info  sigpvc_vcpool = {
51         "sigpvc vcc pool",              /* si_name */
52         sizeof(struct sigpvc_vccb),     /* si_blksiz */
53         10,                             /* si_blkcnt */
54         50                              /* si_maxallow */
55 };
56
57 /*
58  * Local functions
59  */
60 static int      sigpvc_start (void);
61 static int      sigpvc_stop (void);
62 static int      sigpvc_attach (struct sigmgr *, struct atm_pif *);
63 static int      sigpvc_detach (struct atm_pif *);
64 static int      sigpvc_setup (Atm_connvc *, int *);
65 static int      sigpvc_release (struct vccb *, int *);
66 static int      sigpvc_free (struct vccb *);
67 static int      sigpvc_ioctl (int, caddr_t, caddr_t);
68
69 /*
70  * Local variables
71  */
72 static int      sigpvc_registered = 0;
73 static struct sigmgr    sigpvc_mgr = {
74         NULL,
75         ATM_SIG_PVC,
76         NULL,
77         sigpvc_attach,
78         sigpvc_detach,
79         sigpvc_setup,
80         NULL,
81         NULL,
82         sigpvc_release,
83         sigpvc_free,
84         sigpvc_ioctl
85 };
86
87 static struct attr_cause        sigpvc_cause = {
88         T_ATM_PRESENT,
89         {
90                 T_ATM_ITU_CODING,
91                 T_ATM_LOC_USER,
92                 T_ATM_CAUSE_UNSPECIFIED_NORMAL,
93                 {0, 0, 0, 0}
94         }
95 };
96
97
98 /*
99  * Initialize sigpvc processing
100  * 
101  * This will be called during module loading.  We'll just register
102  * the sigpvc protocol descriptor and wait for a SigPVC ATM interface 
103  * to come online.
104  *
105  * Arguments:
106  *      none
107  *
108  * Returns:
109  *      0       startup was successful 
110  *      errno   startup failed - reason indicated
111  *
112  */
113 static int
114 sigpvc_start()
115 {
116         int     err = 0;
117
118         /*
119          * Verify software version
120          */
121         if (atm_version != ATM_VERSION) {
122                 log(LOG_ERR, "version mismatch: sigpvc=%d.%d kernel=%d.%d\n",
123                         ATM_VERS_MAJ(ATM_VERSION), ATM_VERS_MIN(ATM_VERSION),
124                         ATM_VERS_MAJ(atm_version), ATM_VERS_MIN(atm_version));
125                 return (EINVAL);
126         }
127
128         /*
129          * Register ourselves with system
130          */
131         err = atm_sigmgr_register(&sigpvc_mgr);
132         if (err == 0)
133                 sigpvc_registered = 1;
134
135         return (err);
136 }
137
138
139 /*
140  * Halt sigpvc processing 
141  * 
142  * This should be called just prior to unloading the module from
143  * memory.  All sigpvc interfaces must be deregistered before the
144  * protocol can be shutdown.
145  *
146  * Arguments:
147  *      none
148  *
149  * Returns:
150  *      0       shutdown was successful 
151  *      errno   shutdown failed - reason indicated
152  *
153  */
154 static int
155 sigpvc_stop()
156 {
157         int     err = 0;
158         int     s = splnet();
159
160         /*
161          * Is protocol even setup?
162          */
163         if (sigpvc_registered) {
164                 
165                 /*
166                  * Any protocol instances still registered??
167                  */
168                 if (sigpvc_mgr.sm_prinst) {
169
170                         /* Yes, can't stop now */
171                         err = EBUSY;
172                         goto done;
173                 }
174
175                 /*
176                  * De-register from system
177                  */
178                 err = atm_sigmgr_deregister(&sigpvc_mgr);
179                 sigpvc_registered = 0;
180
181                 /*
182                  * Free up our vccb storage pool
183                  */
184                 atm_release_pool(&sigpvc_vcpool);
185         } else
186                 err = ENXIO;
187
188 done:
189         (void) splx(s);
190         return (err);
191 }
192
193
194 /*
195  * Attach a SigPVC-controlled interface
196  * 
197  * Each ATM physical interface must be attached with the signalling manager for
198  * the interface's signalling protocol (via the atm_sigmgr_attach function).  
199  * This function will handle the attachment for SigPVC-controlled interfaces.
200  * A new sigpvc protocol instance will be created and then we'll just sit
201  * around waiting for connection requests.
202  *
203  * Function must be called at splnet.
204  *
205  * Arguments:
206  *      smp     pointer to sigpvc signalling manager control block
207  *      pip     pointer to atm physical interface control block
208  *
209  * Returns:
210  *      0       attach successful 
211  *      errno   attach failed - reason indicated
212  *
213  */
214 static int
215 sigpvc_attach(smp, pip)
216         struct sigmgr   *smp;
217         struct atm_pif  *pip;
218 {
219         int     err = 0;
220         struct sigpvc   *pvp = NULL;
221
222         /*
223          * Allocate sigpvc protocol instance control block
224          */
225         pvp = KM_ALLOC(sizeof(struct sigpvc), M_DEVBUF, M_INTWAIT | M_NULLOK);
226         if (pvp == NULL) {
227                 err = ENOMEM;
228                 goto done;
229         }
230         KM_ZERO(pvp, sizeof(struct sigpvc));
231
232         /*
233          * Link instance into manager's chain
234          */
235         LINK2TAIL((struct siginst *)pvp, struct siginst, 
236                 smp->sm_prinst, si_next);
237
238         /*
239          * Finally, set state and link in interface
240          */
241         pvp->pv_pif = pip;
242         pvp->pv_state = SIGPVC_ACTIVE;
243         pip->pif_sigmgr = smp;
244         pip->pif_siginst = (struct siginst *)pvp;
245
246 done:
247         /*
248          * Reset our work if attach fails
249          */
250         if (err) {
251                 pip->pif_sigmgr = NULL;
252                 pip->pif_siginst = NULL;
253                 if (pvp) {
254                         UNLINK((struct siginst *)pvp, struct siginst, 
255                                 smp->sm_prinst, si_next);
256                         KM_FREE(pvp, sizeof(struct sigpvc), M_DEVBUF);
257                 }
258         }
259
260         return (err);
261 }
262
263
264 /*
265  * Detach a SigPVC-controlled interface
266  * 
267  * Each ATM physical interface may be detached from its signalling manager 
268  * (via the atm_sigmgr_detach function).  This function will handle the 
269  * detachment for all SigPVC-controlled interfaces.  All circuits will be 
270  * immediately terminated.
271  *
272  * Function must be called at splnet.
273  *
274  * Arguments:
275  *      pip     pointer to atm physical interface control block
276  *
277  * Returns:
278  *      0       detach successful 
279  *      errno   detach failed - reason indicated
280  *
281  */
282 static int
283 sigpvc_detach(pip)
284         struct atm_pif  *pip;
285 {
286         struct sigpvc   *pvp;
287         struct vccb     *vcp, *vnext;
288
289         /*
290          * Get SigPVC protocol instance
291          */
292         pvp = (struct sigpvc *)pip->pif_siginst;
293
294         /*
295          * Terminate all of our VCCs
296          */
297         for (vcp = Q_HEAD(pvp->pv_vccq, struct vccb); vcp; vcp = vnext){
298                 u_char  oustate;
299
300                 vnext = Q_NEXT(vcp, struct vccb, vc_sigelem);
301
302                 /*
303                  * Close VCC and notify owner
304                  */
305                 oustate = vcp->vc_ustate;
306                 sigpvc_close_vcc(vcp);
307                 if (oustate == VCCU_OPEN) {
308                         vcp->vc_connvc->cvc_attr.cause = sigpvc_cause;
309                         atm_cm_cleared(vcp->vc_connvc);
310                 }
311         }
312
313         /*
314          * If there are no vcc's queued, then get rid of the protocol 
315          * instance.  
316          */
317         if (Q_HEAD(pvp->pv_vccq, struct vccb) == NULL) {
318                 struct sigmgr   *smp = pip->pif_sigmgr;
319
320                 pip->pif_sigmgr = NULL;
321                 pip->pif_siginst = NULL;
322                 UNLINK((struct siginst *)pvp, struct siginst, smp->sm_prinst, 
323                                 si_next);
324                 KM_FREE(pvp, sizeof(struct sigpvc), M_DEVBUF);
325         } else {
326
327                 /*
328                  * Otherwise, set new state indicating detach in progress.
329                  * The protocol instance will be freed during sigpvc_free 
330                  * processing for the last queued vcc.
331                  */
332                 pvp->pv_state = SIGPVC_DETACH;
333         }
334
335         return (0);
336 }
337
338
339 /*
340  * Open a SigPVC ATM Connection
341  * 
342  * All service user requests to open a VC connection (via atm_open_connection)
343  * over an ATM interface attached to the SigPVC signalling manager are handled 
344  * here.  Only PVC requests are allowed.
345  *
346  * Function will be called at splnet.
347  *
348  * Arguments:
349  *      cvp     pointer to CM's connection VCC
350  *      errp    location to store an error code if CALL_FAILED is returned
351  *
352  * Returns:
353  *      CALL_PROCEEDING - connection establishment is in progress
354  *      CALL_FAILED     - connection establishment failed
355  *      CALL_CONNECTED  - connection has been successfully established
356  *
357  */
358 static int
359 sigpvc_setup(cvp, errp)
360         Atm_connvc      *cvp;
361         int             *errp;
362 {
363         struct sigpvc   *pvp =
364                 (struct sigpvc *)cvp->cvc_attr.nif->nif_pif->pif_siginst;
365         int     ret;
366
367         /*
368          * See what signalling has to say
369          */
370         switch (pvp->pv_state) {
371
372         case SIGPVC_ACTIVE:
373                 break;
374
375         default:
376                 *errp = ENXIO;
377                 ret = CALL_FAILED;
378                 goto done;
379         }
380         
381         /*
382          * Open requested type of connection
383          */
384         switch (cvp->cvc_attr.called.addr.address_format) {
385
386         case T_ATM_PVC_ADDR:
387                 /*
388                  * Create a PVC
389                  */
390                 ret = sigpvc_create_pvc(pvp, cvp, errp);
391                 break;
392
393         default:
394                 *errp = EPROTONOSUPPORT;
395                 ret = CALL_FAILED;
396         }
397
398 done:
399         return (ret);
400 }
401
402
403 /*
404  * Close a SigPVC ATM Connection
405  * 
406  * All service user requests to terminate a previously open VC connection 
407  * (via the atm_close_connection function), which is running over an interface 
408  * attached to the SigPVC signalling manager, are handled here.
409  *
410  * Function will be called at splnet.
411  * 
412  * Arguments:
413  *      vcp     pointer to connection's VC control block
414  *      errp    location to store an error code if CALL_FAILED is returned
415  *
416  * Returns:
417  *      CALL_PROCEEDING - connection termination is in progress
418  *      CALL_FAILED     - connection termination failed
419  *      CALL_CLEARED    - connection has been successfully terminated
420  *
421  */
422 static int
423 sigpvc_release(vcp, errp)
424         struct vccb     *vcp;
425         int             *errp;
426 {
427
428         /*
429          * Make sure VCC is open
430          */
431         if ((vcp->vc_sstate == VCCS_NULL) || (vcp->vc_sstate == VCCS_FREE) ||
432             (vcp->vc_ustate == VCCU_NULL) || (vcp->vc_ustate == VCCU_CLOSED)) {
433                 *errp = EALREADY;
434                 return (CALL_FAILED);
435         }
436
437         /*
438          * Not much else to do except close the vccb
439          */
440         sigpvc_close_vcc(vcp);
441
442         return (CALL_CLEARED);
443 }
444
445
446 /*
447  * Free SigPVC ATM Connection Resources
448  * 
449  * All service user requests to free the resources of a closed VCC connection
450  * (via the atm_free_connection function), which is running over an interface 
451  * attached to the SigPVC signalling manager, are handled here.
452  *
453  * Function will be called at splnet.
454  * 
455  * Arguments:
456  *      vcp     pointer to connection's VCC control block
457  *
458  * Returns:
459  *      0       connection free was successful 
460  *      errno   connection free failed - reason indicated
461  *
462  */
463 static int
464 sigpvc_free(vcp)
465         struct vccb     *vcp;
466 {
467         struct atm_pif  *pip = vcp->vc_pif;
468         struct sigpvc   *pvp = (struct sigpvc *)pip->pif_siginst;
469
470         /*
471          * Make sure VCC has been closed
472          */
473         if ((vcp->vc_ustate != VCCU_CLOSED) || (vcp->vc_sstate != VCCS_FREE))
474                 return (EEXIST);
475
476         /*
477          * Remove vccb from protocol queue
478          */
479         DEQUEUE(vcp, struct vccb, vc_sigelem, pvp->pv_vccq);
480
481         /*
482          * Free vccb storage
483          */
484         vcp->vc_ustate = VCCU_NULL;
485         vcp->vc_sstate = VCCS_NULL;
486         atm_free((caddr_t)vcp);
487
488         /*
489          * If we're detaching and this was the last vcc queued,
490          * get rid of the protocol instance
491          */
492         if ((pvp->pv_state == SIGPVC_DETACH) && 
493             (Q_HEAD(pvp->pv_vccq, struct vccb) == NULL)) {
494                 struct sigmgr   *smp = pip->pif_sigmgr;
495
496                 pip->pif_sigmgr = NULL;
497                 pip->pif_siginst = NULL;
498                 UNLINK((struct siginst *)pvp, struct siginst, smp->sm_prinst, 
499                                 si_next);
500                 KM_FREE(pvp, sizeof(struct sigpvc), M_DEVBUF);
501         }
502
503         return (0);
504 }
505
506
507 /*
508  * Process Signalling Manager PF_ATM ioctls
509  * 
510  * Function will be called at splnet.
511  *
512  * Arguments:
513  *      code    PF_ATM sub-operation code
514  *      data    pointer to code specific parameter data area
515  *      arg1    pointer to code specific argument
516  *
517  * Returns:
518  *      0       request procesed
519  *      errno   error processing request - reason indicated
520  *
521  */
522 static int
523 sigpvc_ioctl(code, data, arg1)
524         int             code;
525         caddr_t         data;
526         caddr_t         arg1;
527 {
528         struct atmdelreq        *adp;
529         struct atminfreq        *aip;
530         struct air_vcc_rsp      avr;
531         struct sigpvc   *pvp;
532         struct vccb     *vcp;
533         Atm_connection  *cop;
534         caddr_t         cp;
535         u_int   vpi, vci;
536         int     i, space, err = 0;
537
538
539         switch (code) {
540
541         case AIOCS_DEL_PVC:
542                 /*
543                  * Delete a PVC
544                  */
545                 adp = (struct atmdelreq *)data;
546                 pvp = (struct sigpvc *)arg1;
547
548                 /*
549                  * Find requested VCC
550                  */
551                 vpi = adp->adr_pvc_vpi;
552                 vci = adp->adr_pvc_vci;
553                 for (vcp = Q_HEAD(pvp->pv_vccq, struct vccb); vcp; 
554                                 vcp = Q_NEXT(vcp, struct vccb, vc_sigelem)) {
555                         if ((vcp->vc_vpi == vpi) && (vcp->vc_vci == vci))
556                                 break;
557                 }
558                 if (vcp == NULL)
559                         return (ENOENT);
560
561                 /*
562                  * Schedule VCC termination
563                  */
564                 err = atm_cm_abort(vcp->vc_connvc, &sigpvc_cause.v);
565                 break;
566
567         case AIOCS_DEL_SVC:
568                 /*
569                  * Delete a SVC
570                  */
571                 err = ENOENT;
572                 break;
573
574         case AIOCS_INF_VCC:
575                 /*
576                  * Get VCC information
577                  */
578                 aip = (struct atminfreq *)data;
579                 pvp = (struct sigpvc *)arg1;
580
581                 cp = aip->air_buf_addr;
582                 space = aip->air_buf_len;
583
584                 /*
585                  * Get info for all VCCs on interface
586                  */
587                 for (vcp = Q_HEAD(pvp->pv_vccq, struct vccb); vcp; 
588                                 vcp = Q_NEXT(vcp, struct vccb, vc_sigelem)) {
589                         /*
590                          * Make sure there's room in user buffer
591                          */
592                         if (space < sizeof(avr)) {
593                                 err = ENOSPC;
594                                 break;
595                         }
596
597                         /*
598                          * Fill in info to be returned
599                          */
600                         (void) snprintf(avr.avp_intf, sizeof(avr.avp_intf),
601                                 "%s%d",
602                                 pvp->pv_pif->pif_name, pvp->pv_pif->pif_unit);
603                         avr.avp_vpi = vcp->vc_vpi;
604                         avr.avp_vci = vcp->vc_vci;
605                         avr.avp_type = vcp->vc_type;
606                         avr.avp_sig_proto = ATM_SIG_PVC;
607                         avr.avp_aal = vcp->vc_connvc->cvc_attr.aal.type;
608                         cop = vcp->vc_connvc->cvc_conn;
609                         if  (cop)
610                                 avr.avp_encaps = cop->co_mpx;
611                         else
612                                 avr.avp_encaps = 0;
613                         KM_ZERO(avr.avp_owners, sizeof(avr.avp_owners));
614                         for (i = 0; cop && i < sizeof(avr.avp_owners);
615                                         cop = cop->co_next,
616                                         i += T_ATM_APP_NAME_LEN+1) {
617                                 strncpy(&avr.avp_owners[i],
618                                         cop->co_endpt->ep_getname(cop->co_toku),
619                                         T_ATM_APP_NAME_LEN);
620                         }
621                         avr.avp_state = vcp->vc_sstate;
622                         avr.avp_daddr.address_format = T_ATM_ABSENT;
623                         avr.avp_dsubaddr.address_format = T_ATM_ABSENT;
624                         avr.avp_ipdus = vcp->vc_ipdus;
625                         avr.avp_opdus = vcp->vc_opdus;
626                         avr.avp_ibytes = vcp->vc_ibytes;
627                         avr.avp_obytes = vcp->vc_obytes;
628                         avr.avp_ierrors = vcp->vc_ierrors;
629                         avr.avp_oerrors = vcp->vc_oerrors;
630                         avr.avp_tstamp = vcp->vc_tstamp;
631
632                         /*
633                          * Copy data to user buffer and update buffer info
634                          */
635                         if ((err = copyout((caddr_t)&avr, cp, sizeof(avr))) != 0)
636                                 break;
637                         cp += sizeof(avr);
638                         space -= sizeof(avr);
639                 }
640
641                 /*
642                  * Update buffer pointer/count
643                  */
644                 aip->air_buf_addr = cp;
645                 aip->air_buf_len = space;
646                 break;
647
648         case AIOCS_INF_ARP:
649         case AIOCS_INF_ASV:
650                 /*
651                  * Get ARP table/server information
652                  */
653                 /* We don't maintain any ARP information */
654                 break;
655
656         default:
657                 err = EOPNOTSUPP;
658         }
659
660         return (err);
661 }
662
663
664 #ifdef ATM_SIGPVC_MODULE
665 /*
666  *******************************************************************
667  *
668  * Loadable Module Support
669  *
670  *******************************************************************
671  */
672 static int      sigpvc_doload (void);
673 static int      sigpvc_dounload (void);
674
675 /*
676  * Generic module load processing
677  * 
678  * This function is called by an OS-specific function when this
679  * module is being loaded.
680  *
681  * Arguments:
682  *      none
683  *
684  * Returns:
685  *      0       load was successful 
686  *      errno   load failed - reason indicated
687  *
688  */
689 static int
690 sigpvc_doload()
691 {
692         int     err = 0;
693
694         /*
695          * Start us up
696          */
697         err = sigpvc_start();
698         if (err)
699                 /* Problems, clean up */
700                 (void)sigpvc_stop();
701
702         return (err);
703 }
704
705
706 /*
707  * Generic module unload processing
708  * 
709  * This function is called by an OS-specific function when this
710  * module is being unloaded.
711  *
712  * Arguments:
713  *      none
714  *
715  * Returns:
716  *      0       unload was successful 
717  *      errno   unload failed - reason indicated
718  *
719  */
720 static int
721 sigpvc_dounload()
722 {
723         int     err = 0;
724
725         /*
726          * OK, try to clean up our mess
727          */
728         err = sigpvc_stop();
729
730         return (err);
731 }
732
733 #include <sys/exec.h>
734 #include <sys/sysent.h>
735 #include <sys/lkm.h>
736
737 /*
738  * Loadable miscellaneous module description
739  */
740 MOD_MISC(sigpvc);
741
742
743 /*
744  * Loadable module support "load" entry point
745  * 
746  * This is the routine called by the lkm driver whenever the
747  * modload(1) command is issued for this module.
748  *
749  * Arguments:
750  *      lkmtp   pointer to lkm drivers's structure
751  *      cmd     lkm command code
752  *
753  * Returns:
754  *      0       command was successful 
755  *      errno   command failed - reason indicated
756  *
757  */
758 static int
759 sigpvc_load(lkmtp, cmd)
760         struct lkm_table        *lkmtp;
761         int             cmd;
762 {
763         return(sigpvc_doload());
764 }
765
766
767 /*
768  * Loadable module support "unload" entry point
769  * 
770  * This is the routine called by the lkm driver whenever the
771  * modunload(1) command is issued for this module.
772  *
773  * Arguments:
774  *      lkmtp   pointer to lkm drivers's structure
775  *      cmd     lkm command code
776  *
777  * Returns:
778  *      0       command was successful 
779  *      errno   command failed - reason indicated
780  *
781  */
782 static int
783 sigpvc_unload(lkmtp, cmd)
784         struct lkm_table        *lkmtp;
785         int             cmd;
786 {
787         return(sigpvc_dounload());
788 }
789
790
791 /*
792  * Loadable module support entry point
793  * 
794  * This is the routine called by the lkm driver for all loadable module
795  * functions for this driver.  This routine name must be specified
796  * on the modload(1) command.  This routine will be called whenever the
797  * modload(1), modunload(1) or modstat(1) commands are issued for this
798  * module.
799  *
800  * Arguments:
801  *      lkmtp   pointer to lkm drivers's structure
802  *      cmd     lkm command code
803  *      ver     lkm version
804  *
805  * Returns:
806  *      0       command was successful 
807  *      errno   command failed - reason indicated
808  *
809  */
810 int
811 sigpvc_mod(lkmtp, cmd, ver)
812         struct lkm_table        *lkmtp;
813         int             cmd;
814         int             ver;
815 {
816         MOD_DISPATCH(sigpvc, lkmtp, cmd, ver,
817                 sigpvc_load, sigpvc_unload, lkm_nullcmd);
818 }
819
820 #else   /* !ATM_SIGPVC_MODULE */
821
822 /*
823  *******************************************************************
824  *
825  * Kernel Compiled Module Support
826  *
827  *******************************************************************
828  */
829 static void     sigpvc_doload (void *);
830
831 SYSINIT(atmsigpvc, SI_SUB_PROTO_END, SI_ORDER_ANY, sigpvc_doload, NULL)
832
833 /*
834  * Kernel initialization
835  * 
836  * Arguments:
837  *      arg     Not used
838  *
839  * Returns:
840  *      none
841  *
842  */
843 static void
844 sigpvc_doload(void *arg)
845 {
846         int     err = 0;
847
848         /*
849          * Start us up
850          */
851         err = sigpvc_start();
852         if (err) {
853                 /* Problems, clean up */
854                 (void)sigpvc_stop();
855
856                 log(LOG_ERR, "ATM SIGPVC unable to initialize (%d)!!\n", err);
857         }
858         return;
859 }
860 #endif  /* ATM_SIGPVC_MODULE */
861