summaryrefslogtreecommitdiffstats
path: root/sys/netatm/spans/spans_if.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netatm/spans/spans_if.c')
-rw-r--r--sys/netatm/spans/spans_if.c1336
1 files changed, 1336 insertions, 0 deletions
diff --git a/sys/netatm/spans/spans_if.c b/sys/netatm/spans/spans_if.c
new file mode 100644
index 0000000..4facf73
--- /dev/null
+++ b/sys/netatm/spans/spans_if.c
@@ -0,0 +1,1336 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ *
+ * @(#) $Id: spans_if.c,v 1.12 1998/08/26 23:29:09 mks Exp $
+ *
+ */
+
+/*
+ * SPANS Signalling Manager
+ * ---------------------------
+ *
+ * External interfaces to SPANS manager. Includes support for
+ * running as a loadable kernel module.
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: spans_if.c,v 1.12 1998/08/26 23:29:09 mks Exp $";
+#endif
+
+#ifndef ATM_SPANS_MODULE
+#include "opt_atm.h"
+#endif
+
+#include <netatm/kern_include.h>
+
+#include "spans_xdr.h"
+#include <netatm/spans/spans_var.h>
+
+/*
+ * Global variables
+ */
+struct sp_info spans_vcpool = {
+ "spans vcc pool", /* si_name */
+ sizeof(struct spans_vccb), /* si_blksiz */
+ 10, /* si_blkcnt */
+ 50 /* si_maxallow */
+};
+
+struct sp_info spans_msgpool = {
+ "spans message pool", /* si_name */
+ sizeof(spans_msg), /* si_blksiz */
+ 10, /* si_blkcnt */
+ 50 /* si_maxallow */
+};
+
+/*
+ * Local functions
+ */
+static int spans_start __P((void));
+static int spans_stop __P((void));
+static int spans_attach __P((struct sigmgr *, struct atm_pif *));
+static int spans_detach __P((struct atm_pif *));
+static int spans_setup __P((Atm_connvc *, int *));
+static int spans_release __P((struct vccb *, int *));
+static int spans_accept __P((struct vccb *, int *));
+static int spans_reject __P((struct vccb *, int *));
+static int spans_ioctl __P((int, caddr_t, caddr_t));
+
+/*
+ * Local variables
+ */
+static struct sigmgr *spans_mgr = NULL;
+
+
+/*
+ * Initialize SPANS processing
+ *
+ * This will be called during module loading. We'll just register
+ * the SPANS protocol descriptor and wait for a SPANS ATM interface
+ * to come online.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 startup was successful
+ * errno startup failed - reason indicated
+ *
+ */
+static int
+spans_start()
+{
+ int err = 0;
+
+ /*
+ * Verify software version
+ */
+ if (atm_version != ATM_VERSION) {
+ log(LOG_ERR, "version mismatch: spans=%d.%d kernel=%d.%d\n",
+ ATM_VERS_MAJ(ATM_VERSION),
+ ATM_VERS_MIN(ATM_VERSION),
+ ATM_VERS_MAJ(atm_version),
+ ATM_VERS_MIN(atm_version));
+ return (EINVAL);
+ }
+
+ /*
+ * Allocate protocol definition structure
+ */
+ spans_mgr = (struct sigmgr *)KM_ALLOC(sizeof(struct sigmgr),
+ M_DEVBUF, M_NOWAIT);
+ if (spans_mgr == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+ KM_ZERO(spans_mgr, sizeof(struct sigmgr));
+
+ /*
+ * Initialize protocol invariant values
+ */
+ spans_mgr->sm_proto = ATM_SIG_SPANS;
+ spans_mgr->sm_attach = spans_attach;
+ spans_mgr->sm_detach = spans_detach;
+ spans_mgr->sm_setup = spans_setup;
+ spans_mgr->sm_release = spans_release;
+ spans_mgr->sm_accept = spans_accept;
+ spans_mgr->sm_reject = spans_reject;
+ spans_mgr->sm_free = spans_free;
+ spans_mgr->sm_ioctl = spans_ioctl;
+
+ /*
+ * Register ourselves with system
+ */
+ err = atm_sigmgr_register(spans_mgr);
+ if (err)
+ goto done;
+
+ /*
+ * Start up Connectionless Service
+ */
+ err = spanscls_start();
+ if (err)
+ goto done;
+
+done:
+ return (err);
+}
+
+
+/*
+ * Halt SPANS processing
+ *
+ * This should be called just prior to unloading the module from
+ * memory. All SPANS interfaces must be deregistered before the
+ * protocol can be shutdown.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 startup was successful
+ * errno startup failed - reason indicated
+ *
+ */
+static int
+spans_stop()
+{
+ int err = 0;
+ int s = splnet();
+
+ /*
+ * Is protocol even set up?
+ */
+ if (spans_mgr) {
+
+ /*
+ * Any protocol instances still registered?
+ */
+ if (spans_mgr->sm_prinst) {
+
+ /* Yes, can't stop now */
+ err = EBUSY;
+ goto done;
+ }
+
+ /*
+ * Stop Connectionless Service
+ */
+ spanscls_stop();
+
+ /*
+ * De-register from system
+ */
+ err = atm_sigmgr_deregister(spans_mgr);
+
+ /*
+ * Free up protocol block
+ */
+ KM_FREE(spans_mgr, sizeof(struct sigmgr), M_DEVBUF);
+ spans_mgr = NULL;
+
+ /*
+ * Free up our storage pools
+ */
+ atm_release_pool(&spans_vcpool);
+ atm_release_pool(&spans_msgpool);
+ } else
+ err = ENXIO;
+
+done:
+ (void) splx(s);
+ return (err);
+}
+
+
+/*
+ * Attach a SPANS-controlled interface
+ *
+ * Each ATM physical interface must be attached with the signalling
+ * manager for the interface's signalling protocol (via the
+ * atm_sigmgr_attach function). This function will handle the
+ * attachment for SPANS-controlled interfaces. A new SPANS protocol
+ * instance will be created and then we'll just sit around waiting for
+ * status or connection requests.
+ *
+ * Function must be called at splnet.
+ *
+ * Arguments:
+ * smp pointer to SPANS signalling manager control block
+ * pip pointer to ATM physical interface control block
+ *
+ * Returns:
+ * 0 attach successful
+ * errno attach failed - reason indicated
+ *
+ */
+static int
+spans_attach(smp, pip)
+ struct sigmgr *smp;
+ struct atm_pif *pip;
+{
+ int err = 0, n = 0, s;
+ struct spans *spp = NULL;
+ struct atm_nif *np;
+
+ ATM_DEBUG2("spans_attach: smp=%x, pip=%x\n", smp, pip);
+
+ /*
+ * Count network interfaces attached to the physical interface.
+ * If there are more or less than one, we have big problems.
+ */
+ np = pip->pif_nif;
+ while (np) {
+ n++;
+ np = np->nif_pnext;
+ }
+ if (n != 1) {
+ err = ETOOMANYREFS;
+ goto done;
+ }
+
+ /*
+ * Allocate SPANS protocol instance control block
+ */
+ spp = (struct spans *)KM_ALLOC(sizeof(struct spans),
+ M_DEVBUF, M_NOWAIT);
+ if (spp == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+ KM_ZERO(spp, sizeof(struct spans));
+
+ /*
+ * Set variables in SPANS protocol instance control block
+ */
+ spp->sp_state = SPANS_INIT;
+ spp->sp_h_epoch = time_second;
+ spp->sp_s_epoch = 0;
+ spp->sp_addr.address_format = T_ATM_ABSENT;
+ spp->sp_addr.address_length = 0;
+ spp->sp_subaddr.address_format = T_ATM_ABSENT;
+ spp->sp_subaddr.address_length = 0;
+ spp->sp_probe_ct = 0;
+ spp->sp_alloc_vci = SPANS_MIN_VCI;
+ spp->sp_alloc_vpi = SPANS_VPI;
+ spp->sp_min_vci = SPANS_MIN_VCI;
+ spp->sp_max_vci = pip->pif_maxvci;
+
+ /*
+ * Link instance into manager's chain
+ */
+ LINK2TAIL((struct siginst *)spp, struct siginst, smp->sm_prinst,
+ si_next);
+
+ /*
+ * Link in interface
+ */
+ spp->sp_pif = pip;
+ pip->pif_sigmgr = smp;
+ pip->pif_siginst = (struct siginst *) spp;
+
+ /*
+ * Kick-start the SPANS protocol
+ */
+ SPANS_TIMER(spp, 0);
+
+ /*
+ * Notify Connectionless Service
+ */
+ err = spanscls_attach(spp);
+
+ /*
+ * Log the fact that we've attached
+ */
+ if (!err)
+ log(LOG_INFO, "spans: attached to interface %s%d\n",
+ pip->pif_name, pip->pif_unit);
+
+done:
+ /*
+ * Reset our work if attach fails
+ */
+ if (err) {
+ if (spp) {
+ SPANS_CANCEL(spp);
+ UNLINK((struct siginst *)spp, struct siginst,
+ smp->sm_prinst, si_next);
+ KM_FREE(spp, sizeof(struct spans), M_DEVBUF);
+ }
+ s = splimp();
+ pip->pif_sigmgr = NULL;
+ pip->pif_siginst = NULL;
+ (void) splx(s);
+ }
+
+ return (err);
+}
+
+
+/*
+ * Detach a SPANS-controlled interface
+ *
+ * Each ATM physical interface may be detached from its signalling
+ * manager (via the atm_sigmgr_detach function). This function will
+ * handle the detachment for all SPANS-controlled interfaces. All
+ * circuits will be immediately terminated.
+ *
+ * Function must be called at splnet.
+ *
+ * Arguments:
+ * pip pointer to ATM physical interface control block
+ *
+ * Returns:
+ * 0 detach successful
+ * errno detach failed - reason indicated
+ *
+ */
+static int
+spans_detach(pip)
+ struct atm_pif *pip;
+{
+ struct spans *spp;
+ struct vccb *vcp, *vnext;
+ Atm_connection *cop;
+ int err;
+
+ ATM_DEBUG1("spans_detach: pip=0x%x\n", pip);
+
+ /*
+ * Get SPANS protocol instance
+ */
+ spp = (struct spans *)pip->pif_siginst;
+
+ /*
+ * Return an error if we're already detaching
+ */
+ if (spp->sp_state == SPANS_DETACH) {
+ return(EALREADY);
+ }
+
+ /*
+ * Cancel any outstanding timer
+ */
+ SPANS_CANCEL(spp);
+
+ /*
+ * Notify Connectionless Service
+ */
+ spanscls_detach(spp);
+
+ /*
+ * Terminate all of our VCCs
+ */
+ for (vcp = Q_HEAD(spp->sp_vccq, struct vccb); vcp; vcp = vnext) {
+
+ vnext = Q_NEXT(vcp, struct vccb, vc_sigelem);
+
+ /*
+ * Don't close the signalling VCC yet
+ */
+ if (vcp->vc_connvc && vcp->vc_connvc->cvc_conn ==
+ spp->sp_conn)
+ continue;
+
+ /*
+ * Close VCC and notify owner
+ */
+ err = spans_clear_vcc(spp, (struct spans_vccb *)vcp);
+ if (err) {
+ log(LOG_ERR, "spans: error %d clearing VCCB 0x%x\n",
+ err, vcp);
+ }
+ }
+
+ /*
+ * Now close the SPANS signalling VCC
+ */
+ if (cop = spp->sp_conn) {
+ err = atm_cm_release(cop, &spans_cause);
+ if (err)
+ ATM_DEBUG2(
+ "spans_detach: close failed for SPANS signalling channel; cop=0x%x, err=%d\n",
+ cop, err);
+ }
+
+
+ /*
+ * Get rid of protocol instance if there are no VCCs queued
+ */
+ if (Q_HEAD(spp->sp_vccq, struct vccb) == NULL) {
+ struct sigmgr *smp = pip->pif_sigmgr;
+
+ pip->pif_sigmgr = NULL;
+ pip->pif_siginst = NULL;
+ UNLINK((struct siginst *)spp, struct siginst,
+ smp->sm_prinst, si_next);
+ KM_FREE(spp, sizeof(struct spans), M_DEVBUF);
+ } else {
+ /*
+ * Otherwise, wait for protocol instance to be freed
+ * during spans_free processing for the last queued VCC.
+ */
+ spp->sp_state = SPANS_DETACH;
+ }
+
+ /*
+ * Log the fact that we've detached
+ */
+ log(LOG_INFO, "spans: detached from interface %s%d\n",
+ pip->pif_name, pip->pif_unit);
+
+ return (0);
+}
+
+
+/*
+ * Open a SPANS ATM Connection
+ *
+ * All service user requests to open a VC connection (via
+ * atm_open_connection) over an ATM interface attached to the SPANS
+ * signalling manager are handled here.
+ *
+ * Function will be called at splnet.
+ *
+ * Arguments:
+ * cvp pointer to user's requested connection parameters
+ * errp pointer to an int for extended error information
+ *
+ * Returns:
+ * CALL_PROCEEDING connection establishment is in progress
+ * CALL_FAILED connection establishment failed
+ * CALL_CONNECTED connection has been successfully established
+ *
+ */
+static int
+spans_setup(cvp, errp)
+ Atm_connvc *cvp;
+ int *errp;
+{
+ struct atm_pif *pip = cvp->cvc_attr.nif->nif_pif;
+ struct spans *spp = (struct spans *)pip->pif_siginst;
+ int rc = 0;
+
+ ATM_DEBUG1("spans_setup: cvp=0x%x\n", cvp);
+
+ /*
+ * Intialize the returned error code
+ */
+ *errp = 0;
+
+ /*
+ * Open the connection
+ */
+ switch (cvp->cvc_attr.called.addr.address_format) {
+ case T_ATM_PVC_ADDR:
+ /*
+ * Create a PVC
+ */
+ *errp = spans_open_vcc(spp, cvp);
+ rc = (*errp ? CALL_FAILED : CALL_CONNECTED);
+ break;
+
+ case T_ATM_SPANS_ADDR:
+
+ /*
+ * Create an SVC
+ */
+ *errp = spans_open_vcc(spp, cvp);
+ rc = (*errp ? CALL_FAILED : CALL_PROCEEDING);
+ break;
+
+ default:
+ *errp = EPROTONOSUPPORT;
+ rc = CALL_FAILED;
+ }
+
+ return (rc);
+}
+
+
+/*
+ * Close a SPANS ATM Connection
+ *
+ * All service user requests to terminate a previously open VC
+ * connection (via the atm_close_connection function), which is running
+ * over an interface attached to the SPANS signalling manager, are
+ * handled here.
+ *
+ * Function will be called at splnet.
+ *
+ * Arguments:
+ * vcp pointer to connection's VC control block
+ * errp pointer to an int for extended error information
+ *
+ * Returns:
+ * CALL_PROCEEDING connection termination is in progress
+ * CALL_FAILED connection termination failed
+ * CALL_CLEARED connection has been successfully terminated
+ *
+ */
+static int
+spans_release(vcp, errp)
+ struct vccb *vcp;
+ int *errp;
+{
+ int rc = 0;
+ struct atm_pif *pip = vcp->vc_pif;
+ struct spans *spp = (struct spans *)pip->pif_siginst;
+
+ ATM_DEBUG1("spans_release: vcp=0x%x\n", vcp);
+
+ /*
+ * Initialize returned error code
+ */
+ *errp = 0;
+
+ /*
+ * Make sure VCC is open
+ */
+ if ((vcp->vc_sstate == SPANS_VC_NULL) ||
+ (vcp->vc_sstate == SPANS_VC_CLOSE) ||
+ (vcp->vc_sstate == SPANS_VC_FREE) ||
+ (vcp->vc_ustate == VCCU_NULL) ||
+ (vcp->vc_ustate == VCCU_CLOSED)) {
+ *errp = EALREADY;
+ return(CALL_FAILED);
+ }
+
+ /*
+ * Validate the connection type (PVC or SVC)
+ */
+ if (!(vcp->vc_type & (VCC_PVC | VCC_SVC))) {
+ *errp = EPROTONOSUPPORT;
+ return(CALL_FAILED);
+ }
+
+ /*
+ * Close the VCCB
+ */
+ *errp = spans_close_vcc(spp, (struct spans_vccb *)vcp, FALSE);
+
+ /*
+ * Set the return code
+ */
+ if (vcp->vc_type & VCC_PVC) {
+ rc = (*errp ? CALL_FAILED : CALL_CLEARED);
+ } else {
+ rc = (*errp ? CALL_FAILED : CALL_PROCEEDING);
+ }
+
+ return (rc);
+}
+
+
+/*
+ * Accept a SPANS Open from a remote host
+ *
+ * A user calls this routine (via the atm_accept_call function)
+ * after it is notified that an open request was received for it.
+ *
+ * Function will be called at splnet.
+ *
+ * Arguments:
+ * vcp pointer to user's VCCB
+ * errp pointer to an int for extended error information
+ *
+ * Returns:
+ * CALL_PROCEEDING connection establishment is in progress
+ * CALL_FAILED connection establishment failed
+ * CALL_CONNECTED connection has been successfully established
+ *
+ */
+static int
+spans_accept(vcp, errp)
+ struct vccb *vcp;
+ int *errp;
+{
+ struct atm_pif *pip = vcp->vc_pif;
+ struct spans *spp = (struct spans *)pip->pif_siginst;
+ struct spans_vccb *svp = (struct spans_vccb *)vcp;
+
+ ATM_DEBUG1("spans_accept: vcp=0x%x\n", vcp);
+
+ /*
+ * Initialize the returned error code
+ */
+ *errp = 0;
+
+ /*
+ * Return an error if we're detaching
+ */
+ if (spp->sp_state == SPANS_DETACH) {
+ *errp = ENETDOWN;
+ ATM_DEBUG0("spans_accept: detaching\n");
+ return(CALL_FAILED);
+ }
+
+ /*
+ * Respond to the open request
+ */
+ *errp = spans_send_open_rsp(spp, svp, SPANS_OK);
+ if (*errp) {
+ ATM_DEBUG0("spans_accept: spans_send_open_rsp failed\n");
+ goto failed;
+ }
+
+ /*
+ * Update the VCC states
+ */
+ svp->sv_sstate = SPANS_VC_OPEN;
+ svp->sv_ustate = VCCU_OPEN;
+
+ return(CALL_CONNECTED);
+
+failed:
+ /*
+ * On error, free the VCCB and return CALL_FAILED
+ */
+ svp->sv_sstate = SPANS_VC_FREE;
+ svp->sv_ustate = VCCU_CLOSED;
+ DEQUEUE(svp, struct spans_vccb, sv_sigelem, spp->sp_vccq);
+ spans_free((struct vccb *)svp);
+
+ return(CALL_FAILED);
+}
+
+
+/*
+ * Reject a SPANS Open from a remote host
+ *
+ * A user calls this routine (via the atm_reject_call function)
+ * after it is notified that an open request was received for it.
+ *
+ * Function will be called at splnet.
+ *
+ * Arguments:
+ * vcp pointer to user's VCCB
+ * errp pointer to an int for extended error information
+ *
+ * Returns:
+ * CALL_CLEARED call request rejected
+ * CALL_FAILED call rejection failed
+ *
+ */
+static int
+spans_reject(vcp, errp)
+ struct vccb *vcp;
+ int *errp;
+{
+ struct atm_pif *pip = vcp->vc_pif;
+ struct spans *spp = (struct spans *)pip->pif_siginst;
+ struct spans_vccb *svp = (struct spans_vccb *)vcp;
+
+ ATM_DEBUG1("spans_reject: vcp=0x%x\n", vcp);
+
+ /*
+ * Initialize the returned error code
+ */
+ *errp = 0;
+
+ /*
+ * Return an error if we're detaching
+ */
+ if (spp->sp_state == SPANS_DETACH) {
+ *errp = ENETDOWN;
+ ATM_DEBUG0("spans_reject: detaching\n");
+ return(CALL_FAILED);
+ }
+
+ ATM_DEBUG1("spans_reject: cause code is %d\n",
+ vcp->vc_connvc->cvc_attr.cause.v.cause_value);
+
+ /*
+ * Clean up the VCCB--the connection manager will free it
+ * spans_close_vcc will send a SPANS open response
+ */
+ if (*errp = spans_close_vcc(spp, svp, TRUE)) {
+ ATM_DEBUG0("spans_reject: spans_close_vcc failed\n");
+ return(CALL_FAILED);
+ }
+
+ return(CALL_CLEARED);
+}
+
+
+/*
+ * Abort a SPANS ATM Connection
+ *
+ * All (non-user) requests to abort a previously open VC connection (via
+ * the atm_abort_connection function), which is running over an
+ * interface attached to the SPANS signalling manager, are handled here.
+ * The VCC owner will be notified of the request, in order to initiate
+ * termination of the connection.
+ *
+ * Function will be called at splnet.
+ *
+ * Arguments:
+ * vcp pointer to connection's VC control block
+ *
+ * Returns:
+ * 0 connection release was succesful
+ * errno connection release failed - reason indicated
+ *
+ */
+int
+spans_abort(vcp)
+ struct vccb *vcp;
+{
+
+ /*
+ * Make sure VCC is available
+ */
+ if ((vcp->vc_sstate == SPANS_VC_NULL) ||
+ (vcp->vc_sstate == SPANS_VC_CLOSE) ||
+ (vcp->vc_sstate == SPANS_VC_FREE) ||
+ (vcp->vc_ustate == VCCU_NULL) ||
+ (vcp->vc_ustate == VCCU_CLOSED)) {
+ return(EALREADY);
+ }
+
+ /*
+ * Only abort once
+ */
+ if (vcp->vc_sstate == SPANS_VC_ABORT) {
+ return (EALREADY);
+ }
+
+ /*
+ * Cancel any timer that might be running
+ */
+ SPANS_VC_CANCEL(vcp);
+
+ /*
+ * Set immediate timer to schedule connection termination
+ */
+ vcp->vc_sstate = SPANS_VC_ABORT;
+ SPANS_VC_TIMER(vcp, 0);
+
+ return (0);
+}
+
+
+/*
+ * Free SPANS ATM connection resources
+ *
+ * All service user requests to free the resources of a closed
+ * VCC connection (via the atm_free_connection function), which
+ * is running over an interface attached to the SigPVC signalling
+ * manager, are handled here.
+ *
+ * Function will be called at splnet.
+ *
+ * Arguments:
+ * vcp pointer to connection's VC control block
+ *
+ * Returns:
+ * 0 connection free was successful
+ * errno connection free failed - reason indicated
+ *
+ */
+int
+spans_free(vcp)
+ struct vccb *vcp;
+{
+ struct atm_pif *pip = vcp->vc_pif;
+ struct spans *spp = (struct spans *)pip->pif_siginst;
+
+ ATM_DEBUG1("spans_free: vcp = 0x%x\n", vcp);
+
+ /*
+ * Make sure VCC has been closed
+ */
+ if ((vcp->vc_ustate != VCCU_CLOSED) ||
+ (vcp->vc_sstate != SPANS_VC_FREE)) {
+ ATM_DEBUG2("spans_free: bad state, sstate=%d, ustate=%d\n",
+ vcp->vc_sstate, vcp->vc_ustate);
+ return(EEXIST);
+ }
+
+ /*
+ * Remove VCCB from protocol queue
+ */
+ DEQUEUE(vcp, struct vccb, vc_sigelem, spp->sp_vccq);
+
+ /*
+ * Free VCCB storage
+ */
+ vcp->vc_ustate = VCCU_NULL;
+ vcp->vc_sstate = SPANS_VC_NULL;
+ atm_free((caddr_t)vcp);
+
+ /*
+ * If we're detaching and this was the last VCC queued,
+ * get rid of the protocol instance
+ */
+ if ((spp->sp_state == SPANS_DETACH) &&
+ (Q_HEAD(spp->sp_vccq, struct vccb) == NULL)) {
+ struct sigmgr *smp = pip->pif_sigmgr;
+
+ pip->pif_sigmgr = NULL;
+ pip->pif_siginst = NULL;
+ UNLINK((struct siginst *)spp, struct siginst, smp->sm_prinst,
+ si_next);
+ KM_FREE(spp, sizeof(struct spans), M_DEVBUF);
+ }
+
+ return (0);
+}
+
+
+/*
+ * SPANS IOCTL support
+ *
+ * Function will be called at splnet.
+ *
+ * Arguments:
+ * code PF_ATM sub-operation code
+ * data pointer to code specific parameter data area
+ * arg1 pointer to code specific argument
+ *
+ * Returns:
+ * 0 request procesed
+ * errno error processing request - reason indicated
+ *
+ */
+static int
+spans_ioctl(code, data, arg1)
+ int code;
+ caddr_t data;
+ caddr_t arg1;
+{
+ struct atmdelreq *adp;
+ struct atminfreq *aip;
+ struct spans *spp;
+ struct spans_vccb *svp;
+ struct air_vcc_rsp rsp;
+ Atm_connection *cop;
+ int buf_len, err = 0, i, vpi, vci;
+ caddr_t buf_addr;
+
+
+ switch (code) {
+
+ case AIOCS_DEL_PVC:
+ case AIOCS_DEL_SVC:
+ /*
+ * Delete a VCC
+ */
+ adp = (struct atmdelreq *)data;
+ spp = (struct spans *)arg1;
+
+ /*
+ * Don't let a user close the SPANS signalling VC or
+ * the SPANS CLS VC
+ */
+ vpi = adp->adr_pvc_vpi;
+ vci = adp->adr_pvc_vci;
+ if ((vpi == SPANS_SIG_VPI && vci == SPANS_SIG_VCI) ||
+ (vpi == SPANS_CLS_VPI &&
+ vci == SPANS_CLS_VCI))
+ return(EINVAL);
+
+ /*
+ * Find requested VCC
+ */
+ for (svp = Q_HEAD(spp->sp_vccq, struct spans_vccb); svp;
+ svp = Q_NEXT(svp, struct spans_vccb, sv_sigelem)) {
+ if ((svp->sv_vpi == vpi) && (svp->sv_vci == vci))
+ break;
+ }
+ if (svp == NULL)
+ return (ENOENT);
+
+ /*
+ * Check VCC type
+ */
+ switch (code) {
+ case AIOCS_DEL_PVC:
+ if (!(svp->sv_type & VCC_PVC)) {
+ return(EINVAL);
+ }
+ break;
+ case AIOCS_DEL_SVC:
+ if (!(svp->sv_type & VCC_SVC)) {
+ return(EINVAL);
+ }
+ break;
+ }
+
+ /*
+ * Schedule VCC termination
+ */
+ err = spans_abort((struct vccb *)svp);
+ break;
+
+ case AIOCS_INF_VCC:
+ /*
+ * Return VCC information
+ */
+ aip = (struct atminfreq *)data;
+ spp = (struct spans *)arg1;
+
+ buf_addr = aip->air_buf_addr;
+ buf_len = aip->air_buf_len;
+
+ /*
+ * Loop through the VCC queue
+ */
+ for (svp = Q_HEAD(spp->sp_vccq, struct spans_vccb); svp;
+ svp = Q_NEXT(svp, struct spans_vccb, sv_sigelem)) {
+ /*
+ * Make sure there's room in the user's buffer
+ */
+ if (buf_len < sizeof(rsp)) {
+ err = ENOSPC;
+ break;
+ }
+
+ /*
+ * Fill out the response struct for the VCC
+ */
+ (void) sprintf(rsp.avp_intf, "%s%d",
+ spp->sp_pif->pif_name,
+ spp->sp_pif->pif_unit);
+ rsp.avp_vpi = svp->sv_vpi;
+ rsp.avp_vci = svp->sv_vci;
+ rsp.avp_type = svp->sv_type;
+ rsp.avp_aal = svp->sv_connvc->cvc_attr.aal.type;
+ rsp.avp_sig_proto = svp->sv_proto;
+ cop = svp->sv_connvc->cvc_conn;
+ if (cop)
+ rsp.avp_encaps = cop->co_mpx;
+ else
+ rsp.avp_encaps = 0;
+ rsp.avp_state = svp->sv_sstate;
+ KM_ZERO(rsp.avp_owners, sizeof(rsp.avp_owners));
+ for (i = 0; cop && i < sizeof(rsp.avp_owners);
+ cop = cop->co_next,
+ i += T_ATM_APP_NAME_LEN+1) {
+ strncpy(&rsp.avp_owners[i],
+ cop->co_endpt->ep_getname(cop->co_toku),
+ T_ATM_APP_NAME_LEN);
+ }
+ rsp.avp_daddr.address_format = T_ATM_SPANS_ADDR;
+ rsp.avp_daddr.address_length =
+ sizeof(Atm_addr_spans);
+ if (svp->sv_type & VCC_OUT) {
+ spans_addr_copy(&svp->sv_conn.con_dst,
+ rsp.avp_daddr.address);
+ } else {
+ spans_addr_copy(&svp->sv_conn.con_src,
+ rsp.avp_daddr.address);
+ }
+ rsp.avp_dsubaddr.address_format = T_ATM_ABSENT;
+ rsp.avp_dsubaddr.address_length = 0;
+ rsp.avp_ipdus = svp->sv_ipdus;
+ rsp.avp_opdus = svp->sv_opdus;
+ rsp.avp_ibytes = svp->sv_ibytes;
+ rsp.avp_obytes = svp->sv_obytes;
+ rsp.avp_ierrors = svp->sv_ierrors;
+ rsp.avp_oerrors = svp->sv_oerrors;
+ rsp.avp_tstamp = svp->sv_tstamp;
+
+ /*
+ * Copy the response into the user's buffer
+ */
+ if (err = copyout((caddr_t)&rsp, buf_addr,
+ sizeof(rsp)))
+ break;
+ buf_addr += sizeof(rsp);
+ buf_len -= sizeof(rsp);
+ }
+
+ /*
+ * Update the buffer pointer and length
+ */
+ aip->air_buf_addr = buf_addr;
+ aip->air_buf_len = buf_len;
+ break;
+
+ case AIOCS_ADD_ARP:
+ case AIOCS_DEL_ARP:
+ case AIOCS_INF_ARP:
+ case AIOCS_INF_ASV:
+ /*
+ * ARP specific ioctl's
+ */
+ err = spansarp_ioctl(code, data, arg1);
+ break;
+
+ default:
+ err = EOPNOTSUPP;
+ }
+
+ return (err);
+}
+
+
+#ifdef ATM_SPANS_MODULE
+/*
+ *******************************************************************
+ *
+ * Loadable Module Support
+ *
+ *******************************************************************
+ */
+static int spans_doload __P((void));
+static int spans_dounload __P((void));
+
+/*
+ * Generic module load processing
+ *
+ * This function is called by an OS-specific function when this
+ * module is being loaded.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 load was successful
+ * errno load failed - reason indicated
+ *
+ */
+static int
+spans_doload()
+{
+ int err = 0;
+
+ /*
+ * Start us up
+ */
+ err = spans_start();
+ if (err)
+ /* Problems, clean up */
+ (void)spans_stop();
+
+ return (err);
+}
+
+
+/*
+ * Generic module unload processing
+ *
+ * This function is called by an OS-specific function when this
+ * module is being unloaded.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 unload was successful
+ * errno unload failed - reason indicated
+ *
+ */
+static int
+spans_dounload()
+{
+ int err = 0;
+
+ /*
+ * OK, try to clean up our mess
+ */
+ err = spans_stop();
+
+ return (err);
+}
+
+
+#ifdef sun
+/*
+ * Loadable driver description
+ */
+struct vdldrv spans_drv = {
+ VDMAGIC_PSEUDO, /* Pseudo Driver */
+ "spans_mod", /* name */
+ NULL, /* dev_ops */
+ NULL, /* bdevsw */
+ NULL, /* cdevsw */
+ 0, /* blockmajor */
+ 0 /* charmajor */
+};
+
+
+/*
+ * Loadable module support entry point
+ *
+ * This is the routine called by the vd driver for all loadable module
+ * functions for this pseudo driver. This routine name must be specified
+ * on the modload(1) command. This routine will be called whenever the
+ * modload(1), modunload(1) or modstat(1) commands are issued for this
+ * module.
+ *
+ * Arguments:
+ * cmd vd command code
+ * vdp pointer to vd driver's structure
+ * vdi pointer to command-specific vdioctl_* structure
+ * vds pointer to status structure (VDSTAT only)
+ *
+ * Returns:
+ * 0 command was successful
+ * errno command failed - reason indicated
+ *
+ */
+int
+spans_mod(cmd, vdp, vdi, vds)
+ int cmd;
+ struct vddrv *vdp;
+ caddr_t vdi;
+ struct vdstat *vds;
+{
+ int err = 0;
+
+ switch (cmd) {
+
+ case VDLOAD:
+ /*
+ * Module Load
+ *
+ * We dont support any user configuration
+ */
+ err = spans_doload();
+ if (err == 0)
+ /* Let vd driver know about us */
+ vdp->vdd_vdtab = (struct vdlinkage *)&spans_drv;
+ break;
+
+ case VDUNLOAD:
+ /*
+ * Module Unload
+ */
+ err = spans_dounload();
+ break;
+
+ case VDSTAT:
+ /*
+ * Module Status
+ */
+
+ /* Not much to say at the moment */
+
+ break;
+
+ default:
+ log(LOG_ERR, "spans_mod: Unknown vd command 0x%x\n", cmd);
+ err = EINVAL;
+ }
+
+ return (err);
+}
+#endif /* sun */
+
+#ifdef __FreeBSD__
+
+#include <sys/exec.h>
+#include <sys/sysent.h>
+#include <sys/lkm.h>
+
+/*
+ * Loadable miscellaneous module description
+ */
+MOD_MISC(spans);
+
+
+/*
+ * Loadable module support "load" entry point
+ *
+ * This is the routine called by the lkm driver whenever the
+ * modload(1) command is issued for this module.
+ *
+ * Arguments:
+ * lkmtp pointer to lkm drivers's structure
+ * cmd lkm command code
+ *
+ * Returns:
+ * 0 command was successful
+ * errno command failed - reason indicated
+ *
+ */
+static int
+spans_load(lkmtp, cmd)
+ struct lkm_table *lkmtp;
+ int cmd;
+{
+ return(spans_doload());
+}
+
+
+/*
+ * Loadable module support "unload" entry point
+ *
+ * This is the routine called by the lkm driver whenever the
+ * modunload(1) command is issued for this module.
+ *
+ * Arguments:
+ * lkmtp pointer to lkm drivers's structure
+ * cmd lkm command code
+ *
+ * Returns:
+ * 0 command was successful
+ * errno command failed - reason indicated
+ *
+ */
+static int
+spans_unload(lkmtp, cmd)
+ struct lkm_table *lkmtp;
+ int cmd;
+{
+ return(spans_dounload());
+}
+
+
+/*
+ * Loadable module support entry point
+ *
+ * This is the routine called by the lkm driver for all loadable module
+ * functions for this driver. This routine name must be specified
+ * on the modload(1) command. This routine will be called whenever the
+ * modload(1), modunload(1) or modstat(1) commands are issued for this
+ * module.
+ *
+ * Arguments:
+ * lkmtp pointer to lkm drivers's structure
+ * cmd lkm command code
+ * ver lkm version
+ *
+ * Returns:
+ * 0 command was successful
+ * errno command failed - reason indicated
+ *
+ */
+int
+spans_mod(lkmtp, cmd, ver)
+ struct lkm_table *lkmtp;
+ int cmd;
+ int ver;
+{
+ MOD_DISPATCH(spans, lkmtp, cmd, ver,
+ spans_load, spans_unload, lkm_nullcmd);
+}
+#endif /* __FreeBSD__ */
+
+#else /* !ATM_SPANS_MODULE */
+
+/*
+ *******************************************************************
+ *
+ * Kernel Compiled Module Support
+ *
+ *******************************************************************
+ */
+static void spans_doload __P((void *));
+
+SYSINIT(atmspans, SI_SUB_PROTO_END, SI_ORDER_ANY, spans_doload, NULL)
+
+/*
+ * Kernel initialization
+ *
+ * Arguments:
+ * arg Not used
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+spans_doload(void *arg)
+{
+ int err = 0;
+
+ /*
+ * Start us up
+ */
+ err = spans_start();
+ if (err) {
+ /* Problems, clean up */
+ (void)spans_stop();
+
+ log(LOG_ERR, "ATM SPANS unable to initialize (%d)!!\n", err);
+ }
+ return;
+}
+#endif /* ATM_SPANS_MODULE */
+
OpenPOWER on IntegriCloud