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