freebsd-dev/sys/netatm/spans/spans_if.c
1999-01-27 22:42:27 +00:00

1338 lines
27 KiB
C

/*
*
* ===================================
* 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.4 1998/12/04 22:54:53 archie Exp $
*
*/
/*
* SPANS Signalling Manager
* ---------------------------
*
* External interfaces to SPANS manager. Includes support for
* running as a loadable kernel module.
*
*/
#ifndef ATM_SPANS_MODULE
#include "opt_atm.h"
#endif
#include <netatm/kern_include.h>
#include "spans_xdr.h"
#include <netatm/spans/spans_var.h>
#ifndef lint
__RCSID("@(#) $Id: spans_if.c,v 1.4 1998/12/04 22:54:53 archie Exp $");
#endif
/*
* 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=%p, pip=%p\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=%p\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 %p\n",
err, vcp);
}
}
/*
* Now close the SPANS signalling VCC
*/
if ((cop = spp->sp_conn) != NULL) {
err = atm_cm_release(cop, &spans_cause);
if (err)
ATM_DEBUG2(
"spans_detach: close failed for SPANS signalling channel; cop=%p, 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=%p\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=%p\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=%p\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=%p\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)) != 0) {
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 = %p\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) snprintf(rsp.avp_intf,
sizeof(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))) != 0)
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 */