3 * ===================================
4 * HARP | Host ATM Research Platform
5 * ===================================
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.
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.
21 * Copyright 1994-1998 Network Computing Services, Inc.
23 * Copies of this Software may be made, however, the above copyright
24 * notice must be reproduced on all copies.
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.10 2006/01/14 13:36:39 swildner Exp $
31 * SPANS Signalling Manager
32 * ---------------------------
34 * External interfaces to SPANS manager. Includes support for
35 * running as a loadable kernel module.
39 #ifndef ATM_SPANS_MODULE
43 #include <netproto/atm/kern_include.h>
45 #include "spans_xdr.h"
46 #include "spans_var.h"
51 struct sp_info spans_vcpool = {
52 "spans vcc pool", /* si_name */
53 sizeof(struct spans_vccb), /* si_blksiz */
58 struct sp_info spans_msgpool = {
59 "spans message pool", /* si_name */
60 sizeof(spans_msg), /* si_blksiz */
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);
81 static struct sigmgr *spans_mgr = NULL;
85 * Initialize SPANS processing
87 * This will be called during module loading. We'll just register
88 * the SPANS protocol descriptor and wait for a SPANS ATM interface
95 * 0 startup was successful
96 * errno startup failed - reason indicated
105 * Verify software version
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));
117 * Allocate protocol definition structure
119 spans_mgr = KM_ALLOC(sizeof(struct sigmgr),
120 M_DEVBUF, M_INTWAIT | M_NULLOK);
121 if (spans_mgr == NULL) {
125 KM_ZERO(spans_mgr, sizeof(struct sigmgr));
128 * Initialize protocol invariant values
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;
141 * Register ourselves with system
143 err = atm_sigmgr_register(spans_mgr);
148 * Start up Connectionless Service
150 err = spanscls_start();
160 * Halt SPANS processing
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.
170 * 0 startup was successful
171 * errno startup failed - reason indicated
182 * Is protocol even set up?
187 * Any protocol instances still registered?
189 if (spans_mgr->sm_prinst) {
191 /* Yes, can't stop now */
197 * Stop Connectionless Service
202 * De-register from system
204 err = atm_sigmgr_deregister(spans_mgr);
207 * Free up protocol block
209 KM_FREE(spans_mgr, sizeof(struct sigmgr), M_DEVBUF);
213 * Free up our storage pools
215 atm_release_pool(&spans_vcpool);
216 atm_release_pool(&spans_msgpool);
227 * Attach a SPANS-controlled interface
229 * Each ATM physical interface must be attached with the signalling
230 * manager for the interface's signalling protocol (via the
231 * atm_sigmgr_attach function). This function will handle the
232 * attachment for SPANS-controlled interfaces. A new SPANS protocol
233 * instance will be created and then we'll just sit around waiting for
234 * status or connection requests.
236 * Function must be called from a critical section.
239 * smp pointer to SPANS signalling manager control block
240 * pip pointer to ATM physical interface control block
243 * 0 attach successful
244 * errno attach failed - reason indicated
248 spans_attach(struct sigmgr *smp, struct atm_pif *pip)
251 struct spans *spp = NULL;
254 ATM_DEBUG2("spans_attach: smp=%p, pip=%p\n", smp, pip);
257 * Count network interfaces attached to the physical interface.
258 * If there are more or less than one, we have big problems.
271 * Allocate SPANS protocol instance control block
273 spp = KM_ALLOC(sizeof(struct spans),
274 M_DEVBUF, M_INTWAIT | M_NULLOK);
279 KM_ZERO(spp, sizeof(struct spans));
282 * Set variables in SPANS protocol instance control block
284 spp->sp_state = SPANS_INIT;
285 spp->sp_h_epoch = time_second;
287 spp->sp_addr.address_format = T_ATM_ABSENT;
288 spp->sp_addr.address_length = 0;
289 spp->sp_subaddr.address_format = T_ATM_ABSENT;
290 spp->sp_subaddr.address_length = 0;
291 spp->sp_probe_ct = 0;
292 spp->sp_alloc_vci = SPANS_MIN_VCI;
293 spp->sp_alloc_vpi = SPANS_VPI;
294 spp->sp_min_vci = SPANS_MIN_VCI;
295 spp->sp_max_vci = pip->pif_maxvci;
298 * Link instance into manager's chain
300 LINK2TAIL((struct siginst *)spp, struct siginst, smp->sm_prinst,
307 pip->pif_sigmgr = smp;
308 pip->pif_siginst = (struct siginst *) spp;
311 * Kick-start the SPANS protocol
316 * Notify Connectionless Service
318 err = spanscls_attach(spp);
321 * Log the fact that we've attached
324 log(LOG_INFO, "spans: attached to interface %s%d\n",
325 pip->pif_name, pip->pif_unit);
329 * Reset our work if attach fails
334 UNLINK((struct siginst *)spp, struct siginst,
335 smp->sm_prinst, si_next);
336 KM_FREE(spp, sizeof(struct spans), M_DEVBUF);
339 pip->pif_sigmgr = NULL;
340 pip->pif_siginst = NULL;
349 * Detach a SPANS-controlled interface
351 * Each ATM physical interface may be detached from its signalling
352 * manager (via the atm_sigmgr_detach function). This function will
353 * handle the detachment for all SPANS-controlled interfaces. All
354 * circuits will be immediately terminated.
356 * Function must be called from a critical section.
359 * pip pointer to ATM physical interface control block
362 * 0 detach successful
363 * errno detach failed - reason indicated
367 spans_detach(struct atm_pif *pip)
370 struct vccb *vcp, *vnext;
374 ATM_DEBUG1("spans_detach: pip=%p\n", pip);
377 * Get SPANS protocol instance
379 spp = (struct spans *)pip->pif_siginst;
382 * Return an error if we're already detaching
384 if (spp->sp_state == SPANS_DETACH) {
389 * Cancel any outstanding timer
394 * Notify Connectionless Service
396 spanscls_detach(spp);
399 * Terminate all of our VCCs
401 for (vcp = Q_HEAD(spp->sp_vccq, struct vccb); vcp; vcp = vnext) {
403 vnext = Q_NEXT(vcp, struct vccb, vc_sigelem);
406 * Don't close the signalling VCC yet
408 if (vcp->vc_connvc && vcp->vc_connvc->cvc_conn ==
413 * Close VCC and notify owner
415 err = spans_clear_vcc(spp, (struct spans_vccb *)vcp);
417 log(LOG_ERR, "spans: error %d clearing VCCB %p\n",
423 * Now close the SPANS signalling VCC
425 if ((cop = spp->sp_conn) != NULL) {
426 err = atm_cm_release(cop, &spans_cause);
429 "spans_detach: close failed for SPANS signalling channel; cop=%p, err=%d\n",
435 * Get rid of protocol instance if there are no VCCs queued
437 if (Q_HEAD(spp->sp_vccq, struct vccb) == NULL) {
438 struct sigmgr *smp = pip->pif_sigmgr;
440 pip->pif_sigmgr = NULL;
441 pip->pif_siginst = NULL;
442 UNLINK((struct siginst *)spp, struct siginst,
443 smp->sm_prinst, si_next);
444 KM_FREE(spp, sizeof(struct spans), M_DEVBUF);
447 * Otherwise, wait for protocol instance to be freed
448 * during spans_free processing for the last queued VCC.
450 spp->sp_state = SPANS_DETACH;
454 * Log the fact that we've detached
456 log(LOG_INFO, "spans: detached from interface %s%d\n",
457 pip->pif_name, pip->pif_unit);
464 * Open a SPANS ATM Connection
466 * All service user requests to open a VC connection (via
467 * atm_open_connection) over an ATM interface attached to the SPANS
468 * signalling manager are handled here.
470 * Function will be called from a critical section.
473 * cvp pointer to user's requested connection parameters
474 * errp pointer to an int for extended error information
477 * CALL_PROCEEDING connection establishment is in progress
478 * CALL_FAILED connection establishment failed
479 * CALL_CONNECTED connection has been successfully established
483 spans_setup(Atm_connvc *cvp, int *errp)
485 struct atm_pif *pip = cvp->cvc_attr.nif->nif_pif;
486 struct spans *spp = (struct spans *)pip->pif_siginst;
489 ATM_DEBUG1("spans_setup: cvp=%p\n", cvp);
492 * Intialize the returned error code
497 * Open the connection
499 switch (cvp->cvc_attr.called.addr.address_format) {
504 *errp = spans_open_vcc(spp, cvp);
505 rc = (*errp ? CALL_FAILED : CALL_CONNECTED);
508 case T_ATM_SPANS_ADDR:
513 *errp = spans_open_vcc(spp, cvp);
514 rc = (*errp ? CALL_FAILED : CALL_PROCEEDING);
518 *errp = EPROTONOSUPPORT;
527 * Close a SPANS ATM Connection
529 * All service user requests to terminate a previously open VC
530 * connection (via the atm_close_connection function), which is running
531 * over an interface attached to the SPANS signalling manager, are
534 * Function will be called from a critical section.
537 * vcp pointer to connection's VC control block
538 * errp pointer to an int for extended error information
541 * CALL_PROCEEDING connection termination is in progress
542 * CALL_FAILED connection termination failed
543 * CALL_CLEARED connection has been successfully terminated
547 spans_release(struct vccb *vcp, int *errp)
550 struct atm_pif *pip = vcp->vc_pif;
551 struct spans *spp = (struct spans *)pip->pif_siginst;
553 ATM_DEBUG1("spans_release: vcp=%p\n", vcp);
556 * Initialize returned error code
561 * Make sure VCC is open
563 if ((vcp->vc_sstate == SPANS_VC_NULL) ||
564 (vcp->vc_sstate == SPANS_VC_CLOSE) ||
565 (vcp->vc_sstate == SPANS_VC_FREE) ||
566 (vcp->vc_ustate == VCCU_NULL) ||
567 (vcp->vc_ustate == VCCU_CLOSED)) {
573 * Validate the connection type (PVC or SVC)
575 if (!(vcp->vc_type & (VCC_PVC | VCC_SVC))) {
576 *errp = EPROTONOSUPPORT;
583 *errp = spans_close_vcc(spp, (struct spans_vccb *)vcp, FALSE);
586 * Set the return code
588 if (vcp->vc_type & VCC_PVC) {
589 rc = (*errp ? CALL_FAILED : CALL_CLEARED);
591 rc = (*errp ? CALL_FAILED : CALL_PROCEEDING);
599 * Accept a SPANS Open from a remote host
601 * A user calls this routine (via the atm_accept_call function)
602 * after it is notified that an open request was received for it.
604 * Function will be called from a critical section.
607 * vcp pointer to user's VCCB
608 * errp pointer to an int for extended error information
611 * CALL_PROCEEDING connection establishment is in progress
612 * CALL_FAILED connection establishment failed
613 * CALL_CONNECTED connection has been successfully established
617 spans_accept(struct vccb *vcp, int *errp)
619 struct atm_pif *pip = vcp->vc_pif;
620 struct spans *spp = (struct spans *)pip->pif_siginst;
621 struct spans_vccb *svp = (struct spans_vccb *)vcp;
623 ATM_DEBUG1("spans_accept: vcp=%p\n", vcp);
626 * Initialize the returned error code
631 * Return an error if we're detaching
633 if (spp->sp_state == SPANS_DETACH) {
635 ATM_DEBUG0("spans_accept: detaching\n");
640 * Respond to the open request
642 *errp = spans_send_open_rsp(spp, svp, SPANS_OK);
644 ATM_DEBUG0("spans_accept: spans_send_open_rsp failed\n");
649 * Update the VCC states
651 svp->sv_sstate = SPANS_VC_OPEN;
652 svp->sv_ustate = VCCU_OPEN;
654 return(CALL_CONNECTED);
658 * On error, free the VCCB and return CALL_FAILED
660 svp->sv_sstate = SPANS_VC_FREE;
661 svp->sv_ustate = VCCU_CLOSED;
662 DEQUEUE(svp, struct spans_vccb, sv_sigelem, spp->sp_vccq);
663 spans_free((struct vccb *)svp);
670 * Reject a SPANS Open from a remote host
672 * A user calls this routine (via the atm_reject_call function)
673 * after it is notified that an open request was received for it.
675 * Function will be called from a critical section.
678 * vcp pointer to user's VCCB
679 * errp pointer to an int for extended error information
682 * CALL_CLEARED call request rejected
683 * CALL_FAILED call rejection failed
687 spans_reject(struct vccb *vcp, int *errp)
689 struct atm_pif *pip = vcp->vc_pif;
690 struct spans *spp = (struct spans *)pip->pif_siginst;
691 struct spans_vccb *svp = (struct spans_vccb *)vcp;
693 ATM_DEBUG1("spans_reject: vcp=%p\n", vcp);
696 * Initialize the returned error code
701 * Return an error if we're detaching
703 if (spp->sp_state == SPANS_DETACH) {
705 ATM_DEBUG0("spans_reject: detaching\n");
709 ATM_DEBUG1("spans_reject: cause code is %d\n",
710 vcp->vc_connvc->cvc_attr.cause.v.cause_value);
713 * Clean up the VCCB--the connection manager will free it
714 * spans_close_vcc will send a SPANS open response
716 if ((*errp = spans_close_vcc(spp, svp, TRUE)) != 0) {
717 ATM_DEBUG0("spans_reject: spans_close_vcc failed\n");
721 return(CALL_CLEARED);
726 * Abort a SPANS ATM Connection
728 * All (non-user) requests to abort a previously open VC connection (via
729 * the atm_abort_connection function), which is running over an
730 * interface attached to the SPANS signalling manager, are handled here.
731 * The VCC owner will be notified of the request, in order to initiate
732 * termination of the connection.
734 * Function will be called from a critical section.
737 * vcp pointer to connection's VC control block
740 * 0 connection release was succesful
741 * errno connection release failed - reason indicated
745 spans_abort(struct vccb *vcp)
749 * Make sure VCC is available
751 if ((vcp->vc_sstate == SPANS_VC_NULL) ||
752 (vcp->vc_sstate == SPANS_VC_CLOSE) ||
753 (vcp->vc_sstate == SPANS_VC_FREE) ||
754 (vcp->vc_ustate == VCCU_NULL) ||
755 (vcp->vc_ustate == VCCU_CLOSED)) {
762 if (vcp->vc_sstate == SPANS_VC_ABORT) {
767 * Cancel any timer that might be running
769 SPANS_VC_CANCEL(vcp);
772 * Set immediate timer to schedule connection termination
774 vcp->vc_sstate = SPANS_VC_ABORT;
775 SPANS_VC_TIMER(vcp, 0);
782 * Free SPANS ATM connection resources
784 * All service user requests to free the resources of a closed
785 * VCC connection (via the atm_free_connection function), which
786 * is running over an interface attached to the SigPVC signalling
787 * manager, are handled here.
789 * Function will be called from a critical section.
792 * vcp pointer to connection's VC control block
795 * 0 connection free was successful
796 * errno connection free failed - reason indicated
800 spans_free(struct vccb *vcp)
802 struct atm_pif *pip = vcp->vc_pif;
803 struct spans *spp = (struct spans *)pip->pif_siginst;
805 ATM_DEBUG1("spans_free: vcp = %p\n", vcp);
808 * Make sure VCC has been closed
810 if ((vcp->vc_ustate != VCCU_CLOSED) ||
811 (vcp->vc_sstate != SPANS_VC_FREE)) {
812 ATM_DEBUG2("spans_free: bad state, sstate=%d, ustate=%d\n",
813 vcp->vc_sstate, vcp->vc_ustate);
818 * Remove VCCB from protocol queue
820 DEQUEUE(vcp, struct vccb, vc_sigelem, spp->sp_vccq);
825 vcp->vc_ustate = VCCU_NULL;
826 vcp->vc_sstate = SPANS_VC_NULL;
827 atm_free((caddr_t)vcp);
830 * If we're detaching and this was the last VCC queued,
831 * get rid of the protocol instance
833 if ((spp->sp_state == SPANS_DETACH) &&
834 (Q_HEAD(spp->sp_vccq, struct vccb) == NULL)) {
835 struct sigmgr *smp = pip->pif_sigmgr;
837 pip->pif_sigmgr = NULL;
838 pip->pif_siginst = NULL;
839 UNLINK((struct siginst *)spp, struct siginst, smp->sm_prinst,
841 KM_FREE(spp, sizeof(struct spans), M_DEVBUF);
849 * SPANS IOCTL support
851 * Function will be called from a critical section.
854 * code PF_ATM sub-operation code
855 * data pointer to code specific parameter data area
856 * arg1 pointer to code specific argument
860 * errno error processing request - reason indicated
864 spans_ioctl(int code, caddr_t data, caddr_t arg1)
866 struct atmdelreq *adp;
867 struct atminfreq *aip;
869 struct spans_vccb *svp;
870 struct air_vcc_rsp rsp;
872 int buf_len, err = 0, i, vpi, vci;
883 adp = (struct atmdelreq *)data;
884 spp = (struct spans *)arg1;
887 * Don't let a user close the SPANS signalling VC or
890 vpi = adp->adr_pvc_vpi;
891 vci = adp->adr_pvc_vci;
892 if ((vpi == SPANS_SIG_VPI && vci == SPANS_SIG_VCI) ||
893 (vpi == SPANS_CLS_VPI &&
894 vci == SPANS_CLS_VCI))
900 for (svp = Q_HEAD(spp->sp_vccq, struct spans_vccb); svp;
901 svp = Q_NEXT(svp, struct spans_vccb, sv_sigelem)) {
902 if ((svp->sv_vpi == vpi) && (svp->sv_vci == vci))
913 if (!(svp->sv_type & VCC_PVC)) {
918 if (!(svp->sv_type & VCC_SVC)) {
925 * Schedule VCC termination
927 err = spans_abort((struct vccb *)svp);
932 * Return VCC information
934 aip = (struct atminfreq *)data;
935 spp = (struct spans *)arg1;
937 buf_addr = aip->air_buf_addr;
938 buf_len = aip->air_buf_len;
941 * Loop through the VCC queue
943 for (svp = Q_HEAD(spp->sp_vccq, struct spans_vccb); svp;
944 svp = Q_NEXT(svp, struct spans_vccb, sv_sigelem)) {
946 * Make sure there's room in the user's buffer
948 if (buf_len < sizeof(rsp)) {
954 * Fill out the response struct for the VCC
956 snprintf(rsp.avp_intf,
957 sizeof(rsp.avp_intf), "%s%d",
958 spp->sp_pif->pif_name,
959 spp->sp_pif->pif_unit);
960 rsp.avp_vpi = svp->sv_vpi;
961 rsp.avp_vci = svp->sv_vci;
962 rsp.avp_type = svp->sv_type;
963 rsp.avp_aal = svp->sv_connvc->cvc_attr.aal.type;
964 rsp.avp_sig_proto = svp->sv_proto;
965 cop = svp->sv_connvc->cvc_conn;
967 rsp.avp_encaps = cop->co_mpx;
970 rsp.avp_state = svp->sv_sstate;
971 KM_ZERO(rsp.avp_owners, sizeof(rsp.avp_owners));
972 for (i = 0; cop && i < sizeof(rsp.avp_owners);
974 i += T_ATM_APP_NAME_LEN+1) {
975 strncpy(&rsp.avp_owners[i],
976 cop->co_endpt->ep_getname(cop->co_toku),
979 rsp.avp_daddr.address_format = T_ATM_SPANS_ADDR;
980 rsp.avp_daddr.address_length =
981 sizeof(Atm_addr_spans);
982 if (svp->sv_type & VCC_OUT) {
983 spans_addr_copy(&svp->sv_conn.con_dst,
984 rsp.avp_daddr.address);
986 spans_addr_copy(&svp->sv_conn.con_src,
987 rsp.avp_daddr.address);
989 rsp.avp_dsubaddr.address_format = T_ATM_ABSENT;
990 rsp.avp_dsubaddr.address_length = 0;
991 rsp.avp_ipdus = svp->sv_ipdus;
992 rsp.avp_opdus = svp->sv_opdus;
993 rsp.avp_ibytes = svp->sv_ibytes;
994 rsp.avp_obytes = svp->sv_obytes;
995 rsp.avp_ierrors = svp->sv_ierrors;
996 rsp.avp_oerrors = svp->sv_oerrors;
997 rsp.avp_tstamp = svp->sv_tstamp;
1000 * Copy the response into the user's buffer
1002 if ((err = copyout((caddr_t)&rsp, buf_addr,
1005 buf_addr += sizeof(rsp);
1006 buf_len -= sizeof(rsp);
1010 * Update the buffer pointer and length
1012 aip->air_buf_addr = buf_addr;
1013 aip->air_buf_len = buf_len;
1021 * ARP specific ioctl's
1023 err = spansarp_ioctl(code, data, arg1);
1034 #ifdef ATM_SPANS_MODULE
1036 *******************************************************************
1038 * Loadable Module Support
1040 *******************************************************************
1042 static int spans_doload (void);
1043 static int spans_dounload (void);
1046 * Generic module load processing
1048 * This function is called by an OS-specific function when this
1049 * module is being loaded.
1055 * 0 load was successful
1056 * errno load failed - reason indicated
1067 err = spans_start();
1069 /* Problems, clean up */
1077 * Generic module unload processing
1079 * This function is called by an OS-specific function when this
1080 * module is being unloaded.
1086 * 0 unload was successful
1087 * errno unload failed - reason indicated
1091 spans_dounload(void)
1096 * OK, try to clean up our mess
1103 #include <sys/exec.h>
1104 #include <sys/sysent.h>
1105 #include <sys/lkm.h>
1108 * Loadable miscellaneous module description
1114 * Loadable module support "load" entry point
1116 * This is the routine called by the lkm driver whenever the
1117 * modload(1) command is issued for this module.
1120 * lkmtp pointer to lkm drivers's structure
1121 * cmd lkm command code
1124 * 0 command was successful
1125 * errno command failed - reason indicated
1129 spans_load(struct lkm_table *lkmtp, int cmd)
1131 return(spans_doload());
1136 * Loadable module support "unload" entry point
1138 * This is the routine called by the lkm driver whenever the
1139 * modunload(1) command is issued for this module.
1142 * lkmtp pointer to lkm drivers's structure
1143 * cmd lkm command code
1146 * 0 command was successful
1147 * errno command failed - reason indicated
1151 spans_unload(struct lkm_table *lkmtp, int cmd)
1153 return(spans_dounload());
1158 * Loadable module support entry point
1160 * This is the routine called by the lkm driver for all loadable module
1161 * functions for this driver. This routine name must be specified
1162 * on the modload(1) command. This routine will be called whenever the
1163 * modload(1), modunload(1) or modstat(1) commands are issued for this
1167 * lkmtp pointer to lkm drivers's structure
1168 * cmd lkm command code
1172 * 0 command was successful
1173 * errno command failed - reason indicated
1177 spans_mod(struct lkm_table *lkmtp, int cmd, int ver)
1179 MOD_DISPATCH(spans, lkmtp, cmd, ver,
1180 spans_load, spans_unload, lkm_nullcmd);
1183 #else /* !ATM_SPANS_MODULE */
1186 *******************************************************************
1188 * Kernel Compiled Module Support
1190 *******************************************************************
1192 static void spans_doload (void *);
1194 SYSINIT(atmspans, SI_SUB_PROTO_END, SI_ORDER_ANY, spans_doload, NULL)
1197 * Kernel initialization
1207 spans_doload(void *arg)
1214 err = spans_start();
1216 /* Problems, clean up */
1219 log(LOG_ERR, "ATM SPANS unable to initialize (%d)!!\n", err);
1223 #endif /* ATM_SPANS_MODULE */