diff options
Diffstat (limited to 'sys/netatm/spans/spans_if.c')
-rw-r--r-- | sys/netatm/spans/spans_if.c | 1336 |
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 */ + |