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