diff options
Diffstat (limited to 'sys/netatm/sigpvc/sigpvc_if.c')
-rw-r--r-- | sys/netatm/sigpvc/sigpvc_if.c | 953 |
1 files changed, 953 insertions, 0 deletions
diff --git a/sys/netatm/sigpvc/sigpvc_if.c b/sys/netatm/sigpvc/sigpvc_if.c new file mode 100644 index 000000000000..4208f29f4cb3 --- /dev/null +++ b/sys/netatm/sigpvc/sigpvc_if.c @@ -0,0 +1,953 @@ +/* + * + * =================================== + * 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: sigpvc_if.c,v 1.13 1998/07/30 22:32:42 mks Exp $ + * + */ + +/* + * PVC-only Signalling Manager + * --------------------------- + * + * External interfaces to SigPVC manager. Includes support for + * running as a loadable kernel module. + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: sigpvc_if.c,v 1.13 1998/07/30 22:32:42 mks Exp $"; +#endif + +#ifndef ATM_SIGPVC_MODULE +#include "opt_atm.h" +#endif + +#include <netatm/kern_include.h> + +#include <netatm/sigpvc/sigpvc.h> +#include <netatm/sigpvc/sigpvc_var.h> + + +/* + * Global variables + */ +struct sp_info sigpvc_vcpool = { + "sigpvc vcc pool", /* si_name */ + sizeof(struct sigpvc_vccb), /* si_blksiz */ + 10, /* si_blkcnt */ + 50 /* si_maxallow */ +}; + +/* + * Local functions + */ +static int sigpvc_start __P((void)); +static int sigpvc_stop __P((void)); +static int sigpvc_attach __P((struct sigmgr *, struct atm_pif *)); +static int sigpvc_detach __P((struct atm_pif *)); +static int sigpvc_setup __P((Atm_connvc *, int *)); +static int sigpvc_release __P((struct vccb *, int *)); +static int sigpvc_free __P((struct vccb *)); +static int sigpvc_ioctl __P((int, caddr_t, caddr_t)); + +/* + * Local variables + */ +static int sigpvc_registered = 0; +static struct sigmgr sigpvc_mgr = { + NULL, + ATM_SIG_PVC, + NULL, + sigpvc_attach, + sigpvc_detach, + sigpvc_setup, + NULL, + NULL, + sigpvc_release, + sigpvc_free, + sigpvc_ioctl +}; + +static struct attr_cause sigpvc_cause = { + T_ATM_PRESENT, + { + T_ATM_ITU_CODING, + T_ATM_LOC_USER, + T_ATM_CAUSE_UNSPECIFIED_NORMAL, + {0, 0, 0, 0} + } +}; + + +/* + * Initialize sigpvc processing + * + * This will be called during module loading. We'll just register + * the sigpvc protocol descriptor and wait for a SigPVC ATM interface + * to come online. + * + * Arguments: + * none + * + * Returns: + * 0 startup was successful + * errno startup failed - reason indicated + * + */ +static int +sigpvc_start() +{ + int err = 0; + + /* + * Verify software version + */ + if (atm_version != ATM_VERSION) { + log(LOG_ERR, "version mismatch: sigpvc=%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); + } + + /* + * Register ourselves with system + */ + err = atm_sigmgr_register(&sigpvc_mgr); + if (err == 0) + sigpvc_registered = 1; + + return (err); +} + + +/* + * Halt sigpvc processing + * + * This should be called just prior to unloading the module from + * memory. All sigpvc interfaces must be deregistered before the + * protocol can be shutdown. + * + * Arguments: + * none + * + * Returns: + * 0 shutdown was successful + * errno shutdown failed - reason indicated + * + */ +static int +sigpvc_stop() +{ + int err = 0; + int s = splnet(); + + /* + * Is protocol even setup? + */ + if (sigpvc_registered) { + + /* + * Any protocol instances still registered?? + */ + if (sigpvc_mgr.sm_prinst) { + + /* Yes, can't stop now */ + err = EBUSY; + goto done; + } + + /* + * De-register from system + */ + err = atm_sigmgr_deregister(&sigpvc_mgr); + sigpvc_registered = 0; + + /* + * Free up our vccb storage pool + */ + atm_release_pool(&sigpvc_vcpool); + } else + err = ENXIO; + +done: + (void) splx(s); + return (err); +} + + +/* + * Attach a SigPVC-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 SigPVC-controlled interfaces. + * A new sigpvc protocol instance will be created and then we'll just sit + * around waiting for connection requests. + * + * Function must be called at splnet. + * + * Arguments: + * smp pointer to sigpvc signalling manager control block + * pip pointer to atm physical interface control block + * + * Returns: + * 0 attach successful + * errno attach failed - reason indicated + * + */ +static int +sigpvc_attach(smp, pip) + struct sigmgr *smp; + struct atm_pif *pip; +{ + int err = 0; + struct sigpvc *pvp = NULL; + + /* + * Allocate sigpvc protocol instance control block + */ + pvp = (struct sigpvc *) + KM_ALLOC(sizeof(struct sigpvc), M_DEVBUF, M_NOWAIT); + if (pvp == NULL) { + err = ENOMEM; + goto done; + } + KM_ZERO(pvp, sizeof(struct sigpvc)); + + /* + * Link instance into manager's chain + */ + LINK2TAIL((struct siginst *)pvp, struct siginst, + smp->sm_prinst, si_next); + + /* + * Finally, set state and link in interface + */ + pvp->pv_pif = pip; + pvp->pv_state = SIGPVC_ACTIVE; + pip->pif_sigmgr = smp; + pip->pif_siginst = (struct siginst *)pvp; + +done: + /* + * Reset our work if attach fails + */ + if (err) { + pip->pif_sigmgr = NULL; + pip->pif_siginst = NULL; + if (pvp) { + UNLINK((struct siginst *)pvp, struct siginst, + smp->sm_prinst, si_next); + KM_FREE(pvp, sizeof(struct sigpvc), M_DEVBUF); + } + } + + return (err); +} + + +/* + * Detach a SigPVC-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 SigPVC-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 +sigpvc_detach(pip) + struct atm_pif *pip; +{ + struct sigpvc *pvp; + struct vccb *vcp, *vnext; + + /* + * Get SigPVC protocol instance + */ + pvp = (struct sigpvc *)pip->pif_siginst; + + /* + * Terminate all of our VCCs + */ + for (vcp = Q_HEAD(pvp->pv_vccq, struct vccb); vcp; vcp = vnext){ + u_char oustate; + + vnext = Q_NEXT(vcp, struct vccb, vc_sigelem); + + /* + * Close VCC and notify owner + */ + oustate = vcp->vc_ustate; + sigpvc_close_vcc(vcp); + if (oustate == VCCU_OPEN) { + vcp->vc_connvc->cvc_attr.cause = sigpvc_cause; + atm_cm_cleared(vcp->vc_connvc); + } + } + + /* + * If there are no vcc's queued, then get rid of the protocol + * instance. + */ + if (Q_HEAD(pvp->pv_vccq, struct vccb) == NULL) { + struct sigmgr *smp = pip->pif_sigmgr; + + pip->pif_sigmgr = NULL; + pip->pif_siginst = NULL; + UNLINK((struct siginst *)pvp, struct siginst, smp->sm_prinst, + si_next); + KM_FREE(pvp, sizeof(struct sigpvc), M_DEVBUF); + } else { + + /* + * Otherwise, set new state indicating detach in progress. + * The protocol instance will be freed during sigpvc_free + * processing for the last queued vcc. + */ + pvp->pv_state = SIGPVC_DETACH; + } + + return (0); +} + + +/* + * Open a SigPVC ATM Connection + * + * All service user requests to open a VC connection (via atm_open_connection) + * over an ATM interface attached to the SigPVC signalling manager are handled + * here. Only PVC requests are allowed. + * + * Function will be called at splnet. + * + * Arguments: + * cvp pointer to CM's connection VCC + * errp location to store an error code if CALL_FAILED is returned + * + * Returns: + * CALL_PROCEEDING - connection establishment is in progress + * CALL_FAILED - connection establishment failed + * CALL_CONNECTED - connection has been successfully established + * + */ +static int +sigpvc_setup(cvp, errp) + Atm_connvc *cvp; + int *errp; +{ + struct sigpvc *pvp = + (struct sigpvc *)cvp->cvc_attr.nif->nif_pif->pif_siginst; + int ret; + + /* + * See what signalling has to say + */ + switch (pvp->pv_state) { + + case SIGPVC_ACTIVE: + break; + + default: + *errp = ENXIO; + ret = CALL_FAILED; + goto done; + } + + /* + * Open requested type of connection + */ + switch (cvp->cvc_attr.called.addr.address_format) { + + case T_ATM_PVC_ADDR: + /* + * Create a PVC + */ + ret = sigpvc_create_pvc(pvp, cvp, errp); + break; + + default: + *errp = EPROTONOSUPPORT; + ret = CALL_FAILED; + } + +done: + return (ret); +} + + +/* + * Close a SigPVC 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 SigPVC signalling manager, are handled here. + * + * Function will be called at splnet. + * + * Arguments: + * vcp pointer to connection's VC control block + * errp location to store an error code if CALL_FAILED is returned + * + * Returns: + * CALL_PROCEEDING - connection termination is in progress + * CALL_FAILED - connection termination failed + * CALL_CLEARED - connection has been successfully terminated + * + */ +static int +sigpvc_release(vcp, errp) + struct vccb *vcp; + int *errp; +{ + + /* + * Make sure VCC is open + */ + if ((vcp->vc_sstate == VCCS_NULL) || (vcp->vc_sstate == VCCS_FREE) || + (vcp->vc_ustate == VCCU_NULL) || (vcp->vc_ustate == VCCU_CLOSED)) { + *errp = EALREADY; + return (CALL_FAILED); + } + + /* + * Not much else to do except close the vccb + */ + sigpvc_close_vcc(vcp); + + return (CALL_CLEARED); +} + + +/* + * Free SigPVC 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 VCC control block + * + * Returns: + * 0 connection free was successful + * errno connection free failed - reason indicated + * + */ +static int +sigpvc_free(vcp) + struct vccb *vcp; +{ + struct atm_pif *pip = vcp->vc_pif; + struct sigpvc *pvp = (struct sigpvc *)pip->pif_siginst; + + /* + * Make sure VCC has been closed + */ + if ((vcp->vc_ustate != VCCU_CLOSED) || (vcp->vc_sstate != VCCS_FREE)) + return (EEXIST); + + /* + * Remove vccb from protocol queue + */ + DEQUEUE(vcp, struct vccb, vc_sigelem, pvp->pv_vccq); + + /* + * Free vccb storage + */ + vcp->vc_ustate = VCCU_NULL; + vcp->vc_sstate = VCCS_NULL; + atm_free((caddr_t)vcp); + + /* + * If we're detaching and this was the last vcc queued, + * get rid of the protocol instance + */ + if ((pvp->pv_state == SIGPVC_DETACH) && + (Q_HEAD(pvp->pv_vccq, struct vccb) == NULL)) { + struct sigmgr *smp = pip->pif_sigmgr; + + pip->pif_sigmgr = NULL; + pip->pif_siginst = NULL; + UNLINK((struct siginst *)pvp, struct siginst, smp->sm_prinst, + si_next); + KM_FREE(pvp, sizeof(struct sigpvc), M_DEVBUF); + } + + return (0); +} + + +/* + * Process Signalling Manager PF_ATM ioctls + * + * 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 +sigpvc_ioctl(code, data, arg1) + int code; + caddr_t data; + caddr_t arg1; +{ + struct atmdelreq *adp; + struct atminfreq *aip; + struct air_vcc_rsp avr; + struct sigpvc *pvp; + struct vccb *vcp; + Atm_connection *cop; + caddr_t cp; + u_int vpi, vci; + int i, space, err = 0; + + + switch (code) { + + case AIOCS_DEL_PVC: + /* + * Delete a PVC + */ + adp = (struct atmdelreq *)data; + pvp = (struct sigpvc *)arg1; + + /* + * Find requested VCC + */ + vpi = adp->adr_pvc_vpi; + vci = adp->adr_pvc_vci; + for (vcp = Q_HEAD(pvp->pv_vccq, struct vccb); vcp; + vcp = Q_NEXT(vcp, struct vccb, vc_sigelem)) { + if ((vcp->vc_vpi == vpi) && (vcp->vc_vci == vci)) + break; + } + if (vcp == NULL) + return (ENOENT); + + /* + * Schedule VCC termination + */ + err = atm_cm_abort(vcp->vc_connvc, &sigpvc_cause.v); + break; + + case AIOCS_DEL_SVC: + /* + * Delete a SVC + */ + err = ENOENT; + break; + + case AIOCS_INF_VCC: + /* + * Get VCC information + */ + aip = (struct atminfreq *)data; + pvp = (struct sigpvc *)arg1; + + cp = aip->air_buf_addr; + space = aip->air_buf_len; + + /* + * Get info for all VCCs on interface + */ + for (vcp = Q_HEAD(pvp->pv_vccq, struct vccb); vcp; + vcp = Q_NEXT(vcp, struct vccb, vc_sigelem)) { + /* + * Make sure there's room in user buffer + */ + if (space < sizeof(avr)) { + err = ENOSPC; + break; + } + + /* + * Fill in info to be returned + */ + (void) sprintf(avr.avp_intf, "%s%d", + pvp->pv_pif->pif_name, pvp->pv_pif->pif_unit); + avr.avp_vpi = vcp->vc_vpi; + avr.avp_vci = vcp->vc_vci; + avr.avp_type = vcp->vc_type; + avr.avp_sig_proto = ATM_SIG_PVC; + avr.avp_aal = vcp->vc_connvc->cvc_attr.aal.type; + cop = vcp->vc_connvc->cvc_conn; + if (cop) + avr.avp_encaps = cop->co_mpx; + else + avr.avp_encaps = 0; + KM_ZERO(avr.avp_owners, sizeof(avr.avp_owners)); + for (i = 0; cop && i < sizeof(avr.avp_owners); + cop = cop->co_next, + i += T_ATM_APP_NAME_LEN+1) { + strncpy(&avr.avp_owners[i], + cop->co_endpt->ep_getname(cop->co_toku), + T_ATM_APP_NAME_LEN); + } + avr.avp_state = vcp->vc_sstate; + avr.avp_daddr.address_format = T_ATM_ABSENT; + avr.avp_dsubaddr.address_format = T_ATM_ABSENT; + avr.avp_ipdus = vcp->vc_ipdus; + avr.avp_opdus = vcp->vc_opdus; + avr.avp_ibytes = vcp->vc_ibytes; + avr.avp_obytes = vcp->vc_obytes; + avr.avp_ierrors = vcp->vc_ierrors; + avr.avp_oerrors = vcp->vc_oerrors; + avr.avp_tstamp = vcp->vc_tstamp; + + /* + * Copy data to user buffer and update buffer info + */ + if (err = copyout((caddr_t)&avr, cp, sizeof(avr))) + break; + cp += sizeof(avr); + space -= sizeof(avr); + } + + /* + * Update buffer pointer/count + */ + aip->air_buf_addr = cp; + aip->air_buf_len = space; + break; + + case AIOCS_INF_ARP: + /* + * Get ARP table information + */ + /* We don't maintain any ARP information */ + break; + + default: + err = EOPNOTSUPP; + } + + return (err); +} + + +#ifdef ATM_SIGPVC_MODULE +/* + ******************************************************************* + * + * Loadable Module Support + * + ******************************************************************* + */ +static int sigpvc_doload __P((void)); +static int sigpvc_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 +sigpvc_doload() +{ + int err = 0; + + /* + * Start us up + */ + err = sigpvc_start(); + if (err) + /* Problems, clean up */ + (void)sigpvc_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 +sigpvc_dounload() +{ + int err = 0; + + /* + * OK, try to clean up our mess + */ + err = sigpvc_stop(); + + return (err); +} + + +#ifdef sun +/* + * Loadable driver description + */ +struct vdldrv sigpvc_drv = { + VDMAGIC_PSEUDO, /* Pseudo Driver */ + "sigpvc_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 +sigpvc_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 = sigpvc_doload(); + if (err == 0) + /* Let vd driver know about us */ + vdp->vdd_vdtab = (struct vdlinkage *)&sigpvc_drv; + break; + + case VDUNLOAD: + /* + * Module Unload + */ + err = sigpvc_dounload(); + break; + + case VDSTAT: + /* + * Module Status + */ + + /* Not much to say at the moment */ + + break; + + default: + log(LOG_ERR, "sigpvc_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(sigpvc); + + +/* + * 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 +sigpvc_load(lkmtp, cmd) + struct lkm_table *lkmtp; + int cmd; +{ + return(sigpvc_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 +sigpvc_unload(lkmtp, cmd) + struct lkm_table *lkmtp; + int cmd; +{ + return(sigpvc_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 +sigpvc_mod(lkmtp, cmd, ver) + struct lkm_table *lkmtp; + int cmd; + int ver; +{ + MOD_DISPATCH(sigpvc, lkmtp, cmd, ver, + sigpvc_load, sigpvc_unload, lkm_nullcmd); +} +#endif /* __FreeBSD__ */ + +#else /* !ATM_SIGPVC_MODULE */ + +/* + ******************************************************************* + * + * Kernel Compiled Module Support + * + ******************************************************************* + */ +static void sigpvc_doload __P((void *)); + +SYSINIT(atmsigpvc, SI_SUB_PROTO_END, SI_ORDER_ANY, sigpvc_doload, NULL) + +/* + * Kernel initialization + * + * Arguments: + * arg Not used + * + * Returns: + * none + * + */ +static void +sigpvc_doload(void *arg) +{ + int err = 0; + + /* + * Start us up + */ + err = sigpvc_start(); + if (err) { + /* Problems, clean up */ + (void)sigpvc_stop(); + + log(LOG_ERR, "ATM SIGPVC unable to initialize (%d)!!\n", err); + } + return; +} +#endif /* ATM_SIGPVC_MODULE */ + |